Regex 正则表达式以匹配前缀的未确定数目
在lex中,应该匹配并捕获以下字符串Regex 正则表达式以匹配前缀的未确定数目,regex,lex,Regex,Lex,在lex中,应该匹配并捕获以下字符串 semic semiconductor semicondu 使用c执行此操作,代码可能如下所示: strlen(str)>=5 && strncmp(str, "semiconductor", strlen(str))==0; 正则表达式或(lex规则和操作)如何做到这一点?前缀标识的正则表达式是: semic(o(n(d(u(c(t(or?)?)?)?)?)?)?)? 这有点吓人,但很容易通过编程创建。(见下文。) 值得注意的是
semic
semiconductor
semicondu
使用c执行此操作,代码可能如下所示:
strlen(str)>=5 && strncmp(str, "semiconductor", strlen(str))==0;
正则表达式或(lex规则和操作)如何做到这一点?前缀标识的正则表达式是:
semic(o(n(d(u(c(t(or?)?)?)?)?)?)?)?
这有点吓人,但很容易通过编程创建。(见下文。)
值得注意的是,上述(f)lex规则只有在伴随着一个回退模式时才真正有用,该模式识别所有其他不匹配的“单词”(对于“单词”的某些定义)。否则,模式将简单地匹配输入流中下一个单词的最长匹配前缀
如果您有很多令牌需要以这种方式处理,那么创建上述模式的任务似乎有点吓人。然而,用一些脚本语言编写预处理器非常容易,可以在调用扫描器定义文件上的(f)lex之前应用这些脚本语言
例如,这里是一个简单的Python程序,它过滤提供的文件(或标准输入),用上面显示的“最长前缀”模式替换分隔符{:
和:}
之间包含的单词:
文件:前缀
注意:您必须chmod a+x前缀
我选择了{:…:}
,因为它不太可能在(f)lex模式或C/C++代码中使用,所以脚本不必尝试验证分隔符出现的上下文。当然,“极不可能”与“不可能”并不相同。另一种方法是让脚本自己计算出每个关键字的必要前缀应该有多长,可能使用每个关键字的最短唯一前缀和一些最小前缀长度的组合
例如:
$ cat scanner.l.in
%option noinput nounput noyywrap nodefault
%{
#import "parse.tab.h"
%}
ws (#.*|[[:space:]])+
%%
{ws} /* Ignore whitespace and comments */ ;
resi{:stor:} { return T_RESISTOR; }
semi { return T_SEMI; }
semic{:onductor:} { return T_SEMICONDUCTOR; }
tran{:sformer:} { return T_TRANSFORMER; }
trac{:k:} { return T_TRACK; }
[[:alpha:]_][[:alnum:]_]*} { yylval.str = strdup(yytext); return ID; }
. { return *yytext; }
$ # The expected command line, probably in a makefile would be
$ # /path/to/prefixify scanner.l.in > scanner.l
$ # followed by flex -o scanner.c scanner.l
$ ./prefixify scanner.l.in
%option noinput nounput noyywrap nodefault
%{
#import "parse.tab.h"
%}
ws (#.*|[[:space:]])+
%%
{ws} /* Ignore whitespace and comments */ ;
resi(s(t(or?)?)?)? { return T_RESISTOR; }
semi { return T_SEMI; }
semic(o(n(d(u(c(t(or?)?)?)?)?)?)?)? { return T_SEMICONDUCTOR; }
tran(s(f(o(r(m(er?)?)?)?)?)?)? { return T_TRANSFORMER; }
track? { return T_TRACK; }
[[:alpha:]_][[:alnum:]_]*} { yylval.str = strdup(yytext); return ID; }
. { return *yytext; }
谢谢,rici。这是在(f)lex规则部分中使用的,还有一些这样的关键字需要标记化。每次将一个字符分组的解决方案是很麻烦的,例如,50个或更多这样的关键字,并且必须匹配前缀的长度不同。@acore:您可以用一个简单的程序生成模式。这就是我在答案中所做的。@acore:如果您展示更多的规则上下文,我可以在答案中添加一个脚本,这可能会对您有更多帮助。我所期望的是像“semic{conductor}”一样作为一个模式来完成您提供的模式所做的工作。@acore:Flex正则表达式没有实现“最长前缀匹配”。事实上,我不能马上想到一个带有该操作符的正则表达式包,尽管我不能声称自己是所有正则表达式类型的专家。但我会在我的答案中添加一个简单的脚本,对flex文件进行预处理。
$ cat scanner.l.in
%option noinput nounput noyywrap nodefault
%{
#import "parse.tab.h"
%}
ws (#.*|[[:space:]])+
%%
{ws} /* Ignore whitespace and comments */ ;
resi{:stor:} { return T_RESISTOR; }
semi { return T_SEMI; }
semic{:onductor:} { return T_SEMICONDUCTOR; }
tran{:sformer:} { return T_TRANSFORMER; }
trac{:k:} { return T_TRACK; }
[[:alpha:]_][[:alnum:]_]*} { yylval.str = strdup(yytext); return ID; }
. { return *yytext; }
$ # The expected command line, probably in a makefile would be
$ # /path/to/prefixify scanner.l.in > scanner.l
$ # followed by flex -o scanner.c scanner.l
$ ./prefixify scanner.l.in
%option noinput nounput noyywrap nodefault
%{
#import "parse.tab.h"
%}
ws (#.*|[[:space:]])+
%%
{ws} /* Ignore whitespace and comments */ ;
resi(s(t(or?)?)?)? { return T_RESISTOR; }
semi { return T_SEMI; }
semic(o(n(d(u(c(t(or?)?)?)?)?)?)?)? { return T_SEMICONDUCTOR; }
tran(s(f(o(r(m(er?)?)?)?)?)?)? { return T_TRANSFORMER; }
track? { return T_TRACK; }
[[:alpha:]_][[:alnum:]_]*} { yylval.str = strdup(yytext); return ID; }
. { return *yytext; }