我正在用jflex编写tokenizer。我需要将像interferon-a
这样的单词匹配为一个令牌,将像interferon-alpha
这样的单词匹配为三个。
显而易见的解决方案是前瞻,但它们在 jflex 中不起作用。对于类似的任务,我编写了一个函数,匹配匹配模式后的一个附加通配符,检查它是否是 java 代码中的空格,并在有或没有匹配字符串的一部分的情况下将其推回。
REGEX = [:letter:]+-[:letter:].
从字符串interferon-alpha
它将匹配interferon-al
. 然后,在 Java 代码部分,它将检查匹配的最后一个字符是否为空格。它不是,所以-al
会被推回去,interferon
返回。
在interferon-a
的情况下,空格将被推回并返回interferon
。
但是,如果匹配的字符串没有任何成功,则此函数不起作用。此外,它似乎很笨重。因此,我想知道是否有任何"更好"的方法来确保以下字符是空格而不实际匹配和返回它。
JFlex 当然有一个前瞻功能,与 (f)lex 相同。与 Java 正则表达式前瞻断言不同,JFlex 前瞻只能在匹配结束时应用,但在其他方面是相似的。JFlex 手册的语义部分对此进行了描述:
在词法规则中,正则表达式
r
后可能跟一个前瞻表达式。前瞻表达式要么是$
(行尾运算符),要么是/
后跟任意正则表达式。在这两种情况下,前瞻都不会被使用,也不会包含在匹配的文本区域中,但在确定哪个规则的匹配时间最长时会考虑它......
所以你当然可以写规则:
[:letter:]+-[:letter:]/s
但是,您不能将这样的规则放在宏定义(REGEX = …
)中,正如手册中也提到的那样(在宏部分中):
右侧的正则表达式必须格式正确,不得包含
^
、/
或$
运算符。
因此,前瞻运算符只能在模式规则中使用。
请注意,s
匹配任何空格字符(包括换行符),而.
与任何换行符都不匹配。我认为这就是导致您评论的原因,即REGEX = [:letter:]+-[:letter:].
"如果匹配的字符串没有任何成功,则不起作用"(我猜您的意思是"在同一行上没有任何成功的东西,并且您打算编写.
而不是.
)。
您可能(取决于您的语言)更喜欢测试非单词字符,而不是测试以下空格:
[:letter:]+-[:letter:]/W
或者将更精确的规范作为一组 Unicode 属性,如W
的定义(也可在 JFlex 手册的链接部分找到)。
说了这么多,我想重复一下我之前对你类似问题的回答中的建议:把更具体的模式放在第一位。例如,使用以下一对模式将保证第一个模式选取带有单个字母后缀的单词,同时避免需要显式回推。
[:letter:]+(-[:letter:])? { /* matches 'interferon' or 'interferon-a' */ }
[:letter:]+/-[:letter:]+ { /* matches only 'interferon' from 'interferon-alpha' */ }
当然,在这种情况下,您可以通过使用{2,}
而不是+
进行第二次重复来轻松避免第二种模式和第一个模式之间的冲突,但依赖模式排序是完全可以的,因为保证模式不重叠通常很不方便。