我正在尝试用JavaScript编写一个词法分析器来查找一个简单的特定于域的语言的标记。我从一个简单的实现开始,它只是尝试匹配一行中当前位置的后续正则表达式,以确定它是否与某些令牌格式匹配并接受它。
问题在于,当这样的正则表达式内部的某些内容不匹配时,整个正则表达式都会失败,所以我不知道哪个字符确实导致它失败。
有没有办法找出导致正则表达式失败的字符串中的位置?
INB4:我不是要求调试我的正则表达式并验证其正确性。它已经正确,匹配正确的字符串并删除不正确的字符串。我只想以编程方式了解正则表达式停止匹配的位置,找出用户输入中不正确的字符的位置,以及它们中有多少是正常的。
有没有办法用简单的正则表达式来实现它,而不是继续实现一个完整的有限状态自动机?
答案 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+$)))?.
这里发生了什么?每个前瞻在最后一个上逐步构建,一次添加一个令牌。因此我们可以分别测试每个令牌。最后的点是可选择的视觉反馈:我们可以在调试器中看到至少有一个字符匹配,但我们不关心该字符,我们只关心捕获组。
^(?=(\w+))?(?=(\w+\d+))?(?=(\w+\d+$))?.
令牌\w+
,因此,逐步测试\w+\d+
令牌\d+
,因此,逐步测试\w+\d+$
令牌有三个捕获组。如果设置了所有三个,则匹配完全成功。如果未设置第3组(与$
一样),则可以说abc123a
导致失败。如果设置了组1但未设置组2(与$
一样),则可以说abc
导致失败。
供参考:失败路径的内部视图
对于它的价值,这里是RegexBuddy调试器的故障路径视图。
答案 1 :(得分:1)
您可以使用否定字符集RegExp
,
[^xyz] [^a-c]
否定或补充的字符集。也就是说,它匹配任何东西 没有括在括号中。您可以指定范围 字符串使用连字符,但如果连字符显示为第一个 或方括号中的最后一个字符,它被视为a 字符连字符作为普通字符集包含在字符集中 字符。
String.prototype.match()
的 index
属性
返回的Array有一个额外的输入属性,其中包含 已解析的原始字符串。另外,它有一个索引 property,表示匹配中从零开始的索引 字符串。
例如,记录字符index
中RegExp
/[^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/
。虽然每个单词都会单独匹配,但整个表达式都会失败。你无法确定Hello
或World
是否匹配 - 独立,两者都是。它们之间的空白也是可用的。