jjzjj

javascript - 找出正则表达式失败的位置

coder 2024-05-11 原文

我正在尝试用 JavaScript 编写一个词法分析器来查找简单的特定领域语言的标记。我从一个简单的实现开始,它只是尝试匹配一行中当前位置的后续正则表达式,以确定它是否匹配某种标记格式并接受它。

问题是,当这样的正则表达式中的某些内容不匹配时,整个正则表达式都会失败,所以我不知道究竟是哪个字符导致它失败。

有没有办法找出导致正则表达式失败的字符串中的位置?

INB4:我不是在询问调试我的正则表达式并验证其正确性。它已经是正确的,匹配正确的字符串并丢弃不正确的字符串。我只想以编程方式知道正则表达式停止匹配的确切位置,找出用户输入中不正确的字符的位置,以及其中有多少是好的。

有没有办法只用简单的正则表达式而不是继续实现一个成熟的有限状态自动机?

最佳答案

简答

There is no such thing as a "position in the string that causes the regular expression to fail".



但是,我将向您展示一种回答相反问题的方法:

At which token in the regex did the engine become unable to match the string?



讨论

在我看来,the position in the string which caused the regular expression to fail 的问题是颠倒的。当引擎用左手向下移动字符串并用右手向下移动模式时,一个匹配六个字符的正则表达式标记可以稍后,由于量词和回溯,在下一个匹配零个字符 - 或扩展以匹配十。

在我看来,一个更合适的问题是:

At which token in the regex did the engine become unable to match the string?



例如,考虑正则表达式 ^\w+\d+$和字符串 abc132z .
\w+实际上可以匹配整个字符串。然而,整个正则表达式都失败了。说正则表达式在字符串末尾失败是否有意义?我不这么认为。考虑一下。

最初,\w+将匹配 abc132z .然后引擎前进到下一个 token :\d+ .在这个阶段,引擎在字符串中回溯,逐渐让\w+放弃2z (因此 \w+ 现在只对应于 abc13 ),允许 \d+匹配 2 .

在这个阶段,$断言失败,因为 z离开了。引擎回溯,让 \w+ ,放弃3字符,然后是 1 (因此 \w+ 现在只对应于 abc ),最终允许 \d+匹配 132 .在每一步,引擎都会尝试 $断言和失败。根据引擎内部结构,可能会发生更多回溯:\d+将再次放弃 2 和 3,然后 \w+将放弃c和b。当引擎最终放弃时,\w+仅匹配初始 a .你能说正则表达式“在“3”上失败了吗?在“b”上?

不。如果您从左到右查看正则表达式模式,您可以争辩说它在 $ 上失败了。 ,因为它是我们无法添加到匹配中的第一个标记。请记住,还有其他方法可以证明这一点。

下,我会给你一个截图来形象化这一点。但首先,让我们看看我们是否可以回答另一个问题。

其他问题

是否有技术可以让我们回答另一个问题:

At which token in the regex did the engine become unable to match the string?



这取决于您的正则表达式。如果您能够将您的正则表达式分割成干净的组件,那么您可以在捕获组内设计一个带有一系列可选前瞻的表达式,从而使匹配始终成功。第一个未设置的捕获组是导致失败的组。

Javascript 在可选的前瞻方面有点吝啬,但你可以这样写:
^(?:(?=(\w+)))?(?:(?=(\w+\d+)))?(?:(?=(\w+\d+$)))?.

在 PCRE、.NET、Python... 中,您可以更紧凑地编写:
^(?=(\w+))?(?=(\w+\d+))?(?=(\w+\d+$))?.

这里会发生什么?每个前瞻都以最后一个前瞻为基础,一次添加一个 token 。因此我们可以分别测试每个 token 。最后的点是视觉反馈的可选花样:我们可以在调试器中看到至少匹配一个字符,但我们不关心那个字符,我们只关心捕获组。
  • 第 1 组测试 \w+ token
  • 第 2 组似乎在测试 \w+\d+ ,因此,它会逐步测试 \d+ token
  • 第 3 组似乎在测试 \w+\d+$ ,因此,它会逐步测试 $ token

  • 共有三个捕获组。如果这三个都设置好了,那么比赛就完全成功了。如果仅未设置第 3 组(如 abc123a ),您可以说 $导致失败。如果设置了组 1 但未设置组 2(如 abc ),您可以说 \d+导致失败。

    供引用:故障路径的内部 View

    值得一提的是,这里是 RegexBuddy 调试器的故障路径 View 。

    关于javascript - 找出正则表达式失败的位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23839481/

    有关javascript - 找出正则表达式失败的位置的更多相关文章

    1. ruby 正则表达式 - 如何替换字符串中匹配项的第 n 个实例 - 2

      在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg

    2. ruby - 即使失败也继续进行多主机测试 - 2

      我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r

    3. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

      我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

    4. ruby - 正则表达式将非英文字母匹配为非单词字符 - 2

      @raw_array[i]=~/[\W]/非常简单的正则表达式。当我用一些非拉丁字母(具体来说是俄语)尝试时,条件是错误的。我能用它做什么? 最佳答案 @raw_array[i]=~/[\p{L}]/使用西里尔字符进行测试。引用:http://www.regular-expressions.info/unicode.html#prop 关于ruby-正则表达式将非英文字母匹配为非单词字符,我们在StackOverflow上找到一个类似的问题: https://

    5. ruby - 正则表达式在哪个位置失败? - 2

      我需要一个非常简单的字符串验证器来显示第一个符号与所需格式不对应的位置。我想使用正则表达式,但在这种情况下,我必须找到与表达式相对应的字符串停止的位置,但我找不到可以做到这一点的方法。(这一定是一种相当简单的方法……也许没有?)例如,如果我有正则表达式:/^Q+E+R+$/带字符串:"QQQQEEE2ER"期望的结果应该是7 最佳答案 一个想法:你可以做的是标记你的模式并用可选的嵌套捕获组编写它:^(Q+(E+(R+($)?)?)?)?然后你只需要计算你获得的捕获组的数量就可以知道正则表达式引擎在模式中停止的位置,你可以确定匹配结束

    6. ruby - 使用 rbenv 和 ruby​​-build 构建 ruby​​ 失败,出现 undefined symbol : SSLv2_method - 2

      我正在尝试在配备ARMv7处理器的SynologyDS215j上安装ruby​​2.2.4或2.3.0。我用了optware-ng安装gcc、make、openssl、openssl-dev和zlib。我根据README中的说明安装了rbenv(版本1.0.0-19-g29b4da7)和ruby​​-build插件。.这些是随optware-ng安装的软件包及其版本binutils-2.25.1-1gcc-5.3.0-6gconv-modules-2.21-3glibc-opt-2.21-4libc-dev-2.21-1libgmp-6.0.0a-1libmpc-1.0.2-1libm

    7. ruby - 有没有办法从 ruby​​ case 语句中访问表达式? - 2

      我想从then子句中访问c​​ase语句表达式,即food="cheese"casefoodwhen"dip"then"carrotsticks"when"cheese"then"#{expr}crackers"else"mayo"end在这种情况下,expr是食物的当前值(value)。在这种情况下,我知道,我可以简单地访问变量food,但是在某些情况下,该值可能无法再访问(array.shift等)。除了将expr移出到局部变量然后访问它之外,是否有直接访问caseexpr值的方法?罗亚附注我知道这个具体示例很简单,只是一个示例场景。 最佳答案

    8. ruby - 正则表达式 - 排除一个字符 - 2

      这是一个例子:s="abcd+subtext@example.com"s.match(/+[^@]*/)Result=>"+subtext"问题是,我不想在其中包含“+”。我希望结果是“潜台词”,没有+ 最佳答案 您可以在正则表达式中使用括号来创建匹配组:s="abcd+subtext@example.com"s=~/\+([^@]*)/&&$1=>"subtext" 关于ruby-正则表达式-排除一个字符,我们在StackOverflow上找到一个类似的问题:

    9. ruby - 如何遍历 Ruby 中所有正则表达式匹配的字符串? - 2

      我们有一个字符串:“”这个正则表达式://i如何从当前字符串中获取所有匹配项? 最佳答案 "".scan(//)参见scan在ruby​​-docs上 关于ruby-如何遍历Ruby中所有正则表达式匹配的字符串?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/6857852/

    10. ruby-on-rails - Ruby 的 'open_uri' 是否在读取或失败后可靠地关闭套接字? - 2

      一段时间以来,我一直在使用open_uri下拉ftp路径作为数据源,但突然发现我几乎连续不断地收到“530抱歉,允许的最大客户端数(95)已经连接。”我不确定我的代码是否有问题,或者是否是其他人在访问服务器,不幸的是,我无法真正确定谁有问题。本质上,我正在读取FTPURI:defself.read_uri(uri)beginuri=open(uri).readuri=="Error"?nil:urirescueOpenURI::HTTPErrornilendend我猜我需要在这里添加一些额外的错误处理代码...我想确保我采取一切预防措施来关闭所有连接,这样我的连接就不是问题所在,但是我

    随机推荐