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

Sas*_*asQ 12 javascript regex lexical-analysis

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

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

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

INB4:我不是在调试我的正则表达式并验证它的正确性.它已经正确,匹配正确的字符串并删除不正确的字符串.我只想以编程方式了解正则表达式停止匹配的位置,找出用户输入中不正确的字符的位置,以及它们中有多少是正常的.

有没有办法用简单的正则表达式来实现它,而不是继续实现一个完整的有限状态自动机?

zx8*_*x81 27

简短的回答

没有"字符串中的位置导致正则表达式失败".

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

正则表达式中的哪个令牌导致引擎无法匹配字符串?

讨论

在我看来,问题the position in the string which caused the regular expression to fail是颠倒的.当引擎向下移动字符串时左手和图案右手,一个正则表达式匹配六个字符可以稍后,因为量词和回溯,减少到匹配零字符下一个或扩展匹配十.

在我看来,一个更恰当的问题是:

正则表达式中的哪个令牌导致引擎无法匹配字符串?

例如,考虑正则表达式^\w+\d+$和字符串abc132z.

\w+可整个字符串所匹配.然而,整个正则表达式失败了.说正则表达式在字符串末尾失败是否有意义?我不这么认为.考虑一下.

最初,\w+将匹配abc132z.然后引擎前进到下一个标记:\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"上?

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

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

其他问题

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

正则表达式中的哪个令牌导致引擎无法匹配字符串?

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

Javascript在可选前瞻上有点吝啬,但你可以这样编写:

^(?:(?=(\w+)))?(?:(?=(\w+\d+)))?(?:(?=(\w+\d+$)))?.
Run Code Online (Sandbox Code Playgroud)

在PCRE,.NET,Python ......你可以更紧凑地写这个:

^(?=(\w+))?(?=(\w+\d+))?(?=(\w+\d+$))?.
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?每个前瞻在最后一个上逐步构建,一次添加一个令牌.因此我们可以分别测试每个令牌.最后的点是可选择的视觉反馈:我们可以在调试器中看到至少有一个字符匹配,但我们不关心该字符,我们只关心捕获组.

  1. 第1组测试\w+令牌
  2. 第2组似乎测试\w+\d+,因此,它逐步测试\d+令牌
  3. 第3组似乎测试\w+\d+$,因此,它逐步测试$令牌

有三个捕获组.如果设置了所有三个,则匹配完全成功.如果仅设置了第3组(如同abc123a),则可以说$导致失败.如果设置了组1但未设置组2(如同abc),则可以说\d+导致失败.

供参考:故障路径的内部视图

对于它的价值,这里是RegexBuddy调试器的故障路径视图.

RegexBuddy Debug


dog*_*ose 0

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

不,没有。正则表达式要么匹配,要么不匹配。两者之间没有什么。

部分表达式可以匹配,但整个模式不能匹配。所以引擎总是需要计算整个表达式:

获取字符串Hello my World和模式/Hello World/。虽然每个单词都会单独匹配,但整个表达式会失败。你无法判断是否Hello匹配World- 独立,两者都是。它们之间的空白也是可用的。