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

时间:2014-05-23 22:59:58

标签: javascript regex lexical-analysis

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

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

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

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

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

3 个答案:

答案 0 :(得分:25)

简短回答

  

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

但是,我会告诉你一个方法来回答相反的问题:

  

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

<强>讨论

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

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

  

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

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

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

最初,\w+将匹配abc132z。然后引擎前进到下一个标记:\d+。在此阶段,引擎在字符串中回溯,逐渐让\w+放弃2z(以便\w+现在只对应abc13),允许{ {1}}匹配\d+

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

没有。如果您从左到右查看正则表达式模式,您可以认为它在a上失败,因为它是我们无法添加到匹配项的第一个令牌。请记住,还有其他方法可以证明这一点。

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

其他问题

是否有技术可以让我们回答其他问题:

  

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

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

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

$

在PCRE,.NET,Python ......你可以写得更紧凑:

^(?:(?=(\w+)))?(?:(?=(\w+\d+)))?(?:(?=(\w+\d+$)))?.

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

  1. 第1组测试^(?=(\w+))?(?=(\w+\d+))?(?=(\w+\d+$))?. 令牌
  2. 第2组似乎测试\w+,因此,逐步测试\w+\d+令牌
  3. 第3组似乎测试\d+,因此,逐步测试\w+\d+$令牌
  4. 有三个捕获组。如果设置了所有三个,则匹配完全成功。如果未设置第3组(与$一样),则可以说abc123a导致失败。如果设置了组1但未设置组2(与$一样),则可以说abc导致失败。

    供参考:失败路径的内部视图

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

    RegexBuddy Debug

答案 1 :(得分:1)

您可以使用否定字符集RegExp

[^xyz]
[^a-c]
     

否定或补充的字符集。也就是说,它匹配任何东西   没有括在括号中。您可以指定范围   字符串使用连字符,但如果连字符显示为第一个   或方括号中的最后一个字符,它被视为a   字符连字符作为普通字符集包含在字符集中   字符。

String.prototype.match()

index属性

  

返回的Array有一个额外的输入属性,其中包含   已解析的原始字符串。另外,它有一个索引   property,表示匹配中从零开始的索引   字符串。

例如,记录字符indexRegExp /[^a-zA-z]/匹配数字的aBcD7zYx

var re = /[^a-zA-Z]/;
var str = "aBcD7zYx";
var i = str.match(re).index;
console.log(i); // 4

答案 2 :(得分:0)

  

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

不,没有。正则表达式匹配或不匹配。介于两者之间。

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

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