Regex 正则表达式以匹配前缀的未确定数目

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?)?)?)?)?)?)?)? 这有点吓人,但很容易通过编程创建。(见下文。) 值得注意的是

在lex中,应该匹配并捕获以下字符串

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; }