一、基本用法:
'x' 匹配字符 'x'
'.’ 除换行符外的任何字符(字节)
'[xyz]’ 字符类别;在这种情况下,模式匹配‘x’、'y'、'z'
'[abj-oZ]’ 具有范围的“字符类”;匹配“ a”,“ b”,“ j”到“ o”中的任何字母或“ Z”
'[^A-Z]’ “否定字符类”,即该类中的字符以外的任何字符。在这种情况下,任何字符都不能包含大写字母。
'[^A-Z\n]’ 除大写字母或换行符外的任何字符
'[a-z]{-}[aeiou]’ 小写辅音
'r*’ 零个或多个r,其中r是任何正则表达式
'r+’ 一个或多个 r
'r?’ 零或一个r(即“可选r”)
'r{2,5}’ 从两到五个
'r{2,}’ 两个或多个
'r{4}’ 恰好4个
'{name}' 扩展“name”定义,把别处定义的name拿过来用
'"[xyz]\"foo"' 文字字符串: [xyz]” foo,外面的""表示是一个字符串,里面的\"表示是一个转义字符,匹配' " '。
'\X' 如果X是'a','b','f','n','r','t'或'v',则ANSI-C解释为'\x'。即普通字符不转义,就是表示'\x'。
否则,为文字“X”(用于转义诸如“ *”之类的运算符)
'\0' 一个NUL字符(ASCII代码0)
'\123’ 八进制值123的字符
'\x2a’ 十六进制值为2a的字符
'(r)' 匹配“ r”;括号用于改变优先级(请参见下文)
'rs' 正则表达式“ r”后跟正则表达式“ s”;称为串联
'r|s' “ r”或“ s”
'r/s’ 一个“ r”,但前提是其后跟一个“ s”。确定此规则是否为最长匹配项时,
将包含用“ s”匹配的文本,但在执行操作之前,该文本将返回到输入。因此,
该操作只会看到与“ r”匹配的文本。这种模式称为尾随上下文。 (flex不能正确
匹配某些“ r / s”组合。有关危险的尾随上下文,请参见限制。)
'^r’ 一个“ r”,但仅在一行的开头(即刚开始扫描时,或在扫描换行符之后)。
'r$’ 一个“ r”,但只能在一行的末尾(即,在换行符之前)。等同于“ r/\n”。
请注意,flex的“换行符”概念与C编译器用来将flex解释为“ \n”的情况完全相同。
特别是,在某些DOS系统上,您必须自己过滤掉输入中的“ \r”,
或显式地将“ r /\r\ n”用作“ r $”。
'<s> r’ 一个“ r”,但仅在起始条件s中(请参阅“起始条件”以了解起始条件)。
'<s1,s2,s3> r’ 同上,但在任何启动条件s1,s2或s3中。
'<*> r’ 任何开始条件下的“ r”,甚至是排他条件。
'<< EOF >>' 文件结束。
‘<s1,s2><<EOF>>’ 在开始条件s1或s2中的文件结束
注意: 当^
在[ ]
内时表示 "非" ,当直接出现在匹配式内表示匹配一行的开头。
二、示例
1. 示例1
code:
%%
"xyz" printf("quoted xyz\n");
abc printf("unquoted abc\n");
123 printf("digit 123");
%%
int main() {
yylex();
return 0;
}
int yywrap() {
return 1;
}
运行过程:
结果分析:
可以看出,当输入为abce时,匹配规则abc匹配成功。其后面的字符e执行默认动作打印。如果这里没有任何规则,默认就是直接回显。并且每次匹配成功后的输出都会进行换行。
2. 示例2
code:
%%
abc printf("unquoted abc\n");
abcd printf("longer\n");
"xyz" printf("quoted xyz\n");
xyz printf("unquoted xyz\n");
# return 0;
%%
int main() {
yylex();
return 0;
}
int yywrap() {
return 1;
}
运行过程:
用flex编译时会出现以下错误:
原因是上面的匹配规则
"xyz" printf("quoted xyz\n");
xyz printf("unquoted xyz\n");
是相同的,即不加 " " 和加都是一个效果。把其中一个去掉之后再编译如下:
输入abcd,可以看到进行匹配的规则是abcd,而不是abc。即flex遵从最长匹配原则。
3. 示例3
code:
[abc] printf("single character\n");
[A-GO-T] printf("character ranges\n");
[a-z]{2,3} printf("2~3 characters\n");
[0-9]+ printf("multiple digits\n");
[[:alnum:]]+ printf("multiple alphanumber\n");
# return 0;
测试结果很有意思。如果没有规则(该规则是c中判断数字和字母的函数,可以匹配数字和字母)
[[:alnum:]]+ printf("multiple alphanumber\n");
则在测试“1a2b3”时会出现
1a2b3
multiple digits
single character
multiple digits
single character
multiple digits
加上这条规则的话,输出
abc
2~3 characters1a2b3
multiple alphanumber
4. 示例4
code:
[^abc] printf("except a b c\n");
^ab$ printf("start with a end with b\n"); //只能是ab
^a.b$ printf("with more characters\n"); //匹配a开头,b结尾,中间不是换行符的任意字符
[.] printf("a dot\n"); // 通配符在[]中就表示一个点(dot)
(foo|bar)+ printf("multiple foo bar\n"); //字符串foo或者字符串bar重复多次
foo|bar+ printf("multiple r\n"); //字符串foo或者字符串bar
"a.b" printf("a.b exactly\n"); //字符串"a.b"
(.|\n)? printf("everything.\n"); //匹配所有
来测试一下效果:
x
except a b c
except a b c
b
everything.
except a b c
ab
start with a end with b
except a b c
axb
with more characters
except a b c
之所以输入x会输出两次except a b c,是因为对\n的处理不够好,导致回车换行符也被视作except a b c。对上述代码进行优化一下
%%
\n printf("\n");
[^abc] printf("except a b c\n");
^ab$ printf("start with a end with b\n");
^a.b$ printf("with more characters\n");
(foo|bar)+ printf("multiple foo bar\n");
foo|bar+ printf("multiple r\n");
"a.b" printf("a.b exactly\n");
(.|\n)? printf("everything.\n");
%%
int main(int argc, char* argv[]) {
yylex();
return 0;
}
int yywrap() {
return 1;
}
再看一下结果:
aa.bb
everything.
a.b exactly
everything.a.b
with more charactersa*b
with more charactersfoo
multiple foo barfoobar
multiple foo barbarr
multiple r
5. 示例5
code:
%%
(.|\n)* printf("everything.\n");
%%
int main(int argc, char* argv[]) {
yylex();
return 0;
}
int yywrap() {
return 1;
}
上述匹配规则是"匹配所有字符"。测试的时候,如果是直接读入文件,直接显示一次执行动作的结果;如果是交互式输入,需要手动输入EOF(Linux下是新行开始的ctrl+D),而且只有在新行按下ctrl + D时,才会把之前所输入的所有字符进行回显。
本文参考:https://zhuanlan.zhihu.com/p/65490271
更详细的flex使用方法:https://zhuanlan.zhihu.com/p/108167693