最有效的前瞻替代品 jflex



我正在用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,}而不是+进行第二次重复来轻松避免第二种模式和第一个模式之间的冲突,但依赖模式排序是完全可以的,因为保证模式不重叠通常很不方便。

最新更新