我正在编写一个编译器。我刚刚开始,所以我创建了扫描仪(或Lexer)。目前,我正在编写一些将由我的扫描仪处理的常规定义。试图创建其中一个,我遇到了下一个问题:
我在RegExr中测试了以下(非常简单)正则表达式:
r = /(a|ab)/
哪里" r"是一个常规的定义;我的意思是,正则表达式只是(a|ab)
。
我认为语言L(r)会是(根据书 Compilers: Principles, Techniques and Tools ):
L(r) = {a, ab}
令人惊讶的是,该工具与{a}
匹配!
所以我的问题是,为什么会出现这种行为?
答案 0 :(得分:2)
正则表达式a|ab
匹配“a”或“ab”(显然),但是当整个输入与正则表达式匹配时,某些工具/语言(例如Java)会将输入视为匹配,而其他人(例如JavaScript)认为输入匹配输入的某些匹配。
您的工具必须是“某种”品种才能匹配“{a}”。
答案 1 :(得分:1)
正则表达式从左到右解析文本,如果是交流发电机(|
),它首先要与第一个候选人匹配。
如果您使用:
(ab|a)
它会匹配ab
和a
&#39>。
重点是,一旦找到匹配,全局匹配器将在第一场比赛结束后>> 开始下一场比赛尝试。
您可以轻松验证匹配的语言是{a,ab}
:使用正则表达式^c(a|ab)d
并使用cabd
。在这种情况下,正则表达式别无选择,只能选择第二个选项。
所以说正则表达式是:(a|ab)
,文本是ab
。它会与a
匹配,然后会在a
之后开始,因此会尝试与b
匹配,但会失败。
然而,大多数词法分析器工具使用不同的方法来确定匹配。对于词法工具," 最长匹配"计数。所以与最长字符数匹配。
现在,如果您输入(a|ba)
作为正则表达式,它将在之前的ba
之前匹配。为什么?因为它也旨在寻找第一次尝试。在文本cbad
中,从索引1
(b
)开始被认为比从索引2
(a
)开始更好。
答案 2 :(得分:0)
正如@bohemian所说,如果你想匹配整个字符串,一些正则表达式只评估字符串的一部分你可以使用这样的正则表达式:
/^(a|ab)$/
仅接受 a 或 ab