这里是一个针对此问题的极简C++ flex lexer。非贪婪匹配的关键在于flex手册和其他地方提到的起始条件。
起始条件只是lexer的另一个状态。当需要非贪婪匹配时,有一些模式需要在其第一次出现时终止匹配。
通常情况下,无论状态如何,如果您正在寻找目标字符串或模式,则只需确保没有其他更一般的模式可以匹配包含目标模式的更长的输入。
当目标模式有条件且需要在先前匹配后启用时,启动条件很有帮助。您可以打开启动条件以启用匹配目标模式,并通过将状态重置为0或INITIAL
-或者切换到另一个状态进行更多的条件匹配来关闭它。
使用BEGIN
切换状态-还有用于通过yy_push_state
和yy_pop_state
进行状态堆栈操作。
在flex手册中有许多起始条件的示例。
以下是展示使用flex起始条件进行非贪婪匹配的flex规则- lexer将匹配行上dog的第一次出现,直到cat的第一次出现- 匹配不区分大小写。
完整的文件已发布在末尾 - 对于不熟悉flex的人,请注意许多行以空格开头 - 这不是偶然的,而是flex所必需的。
%%
string match;
dog {
BEGIN(HAVE_DOG);
match = yytext;
}
<HAVE_DOG>. match += yytext;
<HAVE_DOG>cat {
match += yytext;
cout << match << "\n";
BEGIN(SKIP_LINE);
}
<HAVE_DOG>\n BEGIN(0);
<SKIP_LINE>{
.*
\n BEGIN(0);
}
.|\n
这是一些测试输入
$ cat dogcat.in.txt
Dog Ca Cat Cc Cat
dog Ca cat Cc cat
dOg Ca cAt Cc cAt
DOG CA CAT CC CAT
cat dog dog cat cat
dog kitten cat dog cat
dig cat dog can dog cut
dig dug dog cow cat cat
doc dogcat catdog
dog dog dog
cat cat cat
使用以下工具构建
flex -o dogcat.flex.cpp dogcat.flex.l && g++ -o dogcat dogcat.flex.cpp
运行
$ ./dogcat < dogcat.in.txt
Dog Ca Cat
dog Ca cat
dOg Ca cAt
DOG CA CAT
dog dog cat
dog kitten cat
dog cow cat
dogcat
完整的 Flex 文件
%option c++
%option case-insensitive
%option main
%option nodefault
%option debug
%x HAVE_DOG
%x SKIP_LINE
%{
#include <string>
#include <iostream>
#ifndef yyFlexLexerOnce
# include <FlexLexer.h>
#endif
using namespace std;
namespace {
yyFlexLexer lexer;
int yylex() {
return lexer.yylex();
}
}
%}
%%
string match;
dog {
BEGIN(HAVE_DOG);
match = yytext;
}
<HAVE_DOG>. match += yytext;
<HAVE_DOG>cat {
match += yytext;
cout << match << "\n";
BEGIN(SKIP_LINE);
}
<HAVE_DOG>\n BEGIN(0);
<SKIP_LINE>{
.*
\n BEGIN(0);
}
.|\n