当我对此代码运行flex时,它会抱怨unrecognized rule
。我希望匹配(b|B)^n(a|A)^m
之类的字符串,以便n >= 4 and m <= 3
。我在regex101上测试了正则表达式,它运行正常。这是代码:
%{
#include <stdio.h>
...
%}
* some rules *
STRING ([bB]{4,}[aA]{1,3}(?!(a|A)+))+ // rule causing error
%%
...
{STRING} {
printf("%s ", yytext);
}
编辑:应匹配整个字符串,并允许分隔符为whitespace
和\或comma
。不应匹配子字符串。
答案 0 :(得分:3)
(F)lex没有实现negative lookahead assertions。 (注意:前面的链接不是认可。)
您可以在flex manual中找到flex接受的正则表达式运算符的完整列表;如果语法不在该列表中,则无论在线正则表达式服务告诉您什么,都不会识别它。 (注意:前面的链接是认可。)
(F)lex确实实现了一个积极的先行断言,但只是在模式的最后。这用trailing context operator /
表示。你可以使用该运算符来识别你的令牌,要求它后跟 A 以外的其他东西:
[bB]{4,}[aA]{1,3}/[^Aa] { printf("%s ", yytext); }
但这并不是完全相同的语义,因为它不会在输入的最后识别令牌。它要求令牌后跟某些,而不是 A ;开始后跟没有不计算在内。 (实际上,这可能没什么区别。如果您正在扫描文本流中的输入,您可以合理地期望该流将换行符作为最后一个字符,并且换行符将与[^Aa]
匹配。但是,如果您打算扫描可能根本没有换行的文本字符串,那么您需要知道这个问题。)
大多数时候,这不是你想要的。或者,如果它真的是你想要的,那么(f)lex可能不适合你的用例。
(F)lex旨在将输入划分为连续的令牌。它不搜索令牌;它标识当前输入点的令牌。它期望整个输入将由标记组成,因此某些模式需要在每个点匹配。
在此基础上,您需要考虑不匹配序列是什么类型的令牌。举个例子:
bbbbbbbaaaa
有太多 a s是&#34;字符串&#34;与你的规则。那是什么?
有效令牌bbbbbbbaaa
后跟另一个以 a 开头的令牌?
与其他模式匹配的有效令牌? (例如LONG_STRING
)?
应忽略的无效令牌,允许扫描继续?
无法恢复的错误?
可以在不使用任何环视操作符的情况下处理所有这些情况。
在第一种情况下,使用与有效令牌匹配的正则表达式就足够了:
[bB]{4,}[aA]{1,3} { printf("Valid STRING: %s ", yytext); }
在第二种情况下,您可以依赖(f)lex最大咬合匹配规则,该规则指出将使用与最长匹配相对应的模式:
[bB]{4,}[aA]{1,3} { printf("Valid STRING: %s ", yytext); }
[bB]{4,}[aA]{4,} { printf("Valid LONG STRING: %s ", yytext); }
可以简化:
[bB]{4,}[aA]{1,3} { printf("Valid STRING: %s ", yytext); }
[bB]{4,}[aA] { printf("Valid LONG STRING: %s ", yytext); }
这将具有相同的效果,因为(f)lex规则决定两个具有最长匹配的模式是使用输入文件中的第一个模式。因此bbbbaa---
的前六个字符匹配两个模式,因此第一个字符获胜,而bbbbaaaa---
与第一个模式匹配七个字符,与第二个模式匹配八个字符,因此第二个获胜。
对于第三和第四种情况,也可以使用上述图案对;唯一的区别在于对应于第二种模式的动作。对于案例3:忽略令牌,可能发出警告;对于案例4:产生错误消息并终止扫描。