flex学习 - 模式
第四章模式
输入中的模式(参见规则部分)是使用一组扩展的正则表达式编写的。它们是:
'x'
匹配字符'x'
'.'
除了换行符的任何字符(字节)
'[xyz]'
一个字符类;在这种情况中,模式匹配'x','y'或'z'
'[abj-oZ]'
一个范围内的字符类;匹配a,b,j-o范围内的一个字符,或Z
'[^A-Z]'
一个否定的字符类;如不在这个类中的任何字符。在这种情况下,是除了大写字母外的任何字符。
'[^A-Z\n]'
除了大写字母和换行符的任何字符
'[a-z]{-}[aeiou]'
小写的辅音
'r'
0个或多个r,这里的r是任何的正则表达式
'r+'
1个或多个r
'r?'
0个或1个r(也就是一个可选的r)
'r{2,5}'
2个到5个r
'r{2,}'
2个或更多的r
'r{4}'
精确的4个r
'{name}'
name定义的扩展
'"[xyz]"foo"'
字符串字面值:'[xyz]"foo'
'\X'
如果X是a,b,f,n,r,t或v,则是ANSI-C的'\x'解释。其它的,字面值X(用于转义等操作符)
'\0'
一个NUL字符(ASCII代码0)
'\123'
8进制123的字符
'\x2a'
16进制值2a字符
'(r)'
匹配r;括号用于覆盖优先级(见下文)
'(?r-s:pattern)'
在解释模式时应用选项r并忽略选项s。选项可以是0个或多个字符i,s或x。
'i' 意味着不区分大小写。'-i' 意味着区分大小写
's' 改变'.'的意思为语法来匹配任何单个字节。'-s'改变'.'的意思为匹配除了'\n'外的任何字节
'x' 忽略在模式中的注释和空白。空格将被忽略,除非它被反斜杠转义,包含在'""'中,或者出现在字符类中。
下面都是有效的:
(?:foo) same as (foo)
(?i:ab7) same as ([aA][bB]7)
(?-i:ab) same as (ab)
(?s:.) same as [\x00-\xFF]
(?-s:.) same as [^\n]
(?ix-s: a . b) same as ([Aa][^\n][bB])
(?x:a b) same as ("ab")
(?x:a\ b) same as ("a b")
(?x:a" "b) same as ("a b")
(?x:a[ ]b) same as ("a b")
(?x:a
/* comment /
b
c) same as (abc)
'(?# comment )'
省略'()'中的所有内容。遇到的第一个')'字符结束模式。注释中不可能包含')'字符。注释可以跨行。
'rs'
正则表达式r后面跟着正则表达式s;称为串联
'r|s'
r或s中的一个
'r/s'
一个r,但前提是后面跟着一个s。在确定该规则是否为最长匹配时,包含s匹配的文本,但在执行操作之前将其返回到输入。所以操作只看到与r匹配的文本。这种类型的模式称为尾随上下文。(有一些r/s的组合,flex不能正确匹配。请参阅限制,了解危险的尾随上下文。)
'^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,甚至是专有的一个
'<
文件结束
'<s1,s2><
以s1或s2开始条件的文件结束
注意,在字符类内部,除了转义()和字符类操作父'-',']]'以及类开头的'^'外,所有的正则表达式操作符都失去了其特殊含义。
上面列出的正则表达式按照优先级进行分组,从最高优先级到最低优先级。这些组合在一起具有相同的优先级(请参阅--posix POSIX遵从选项文档中关于重复操作符{}优先级的特殊说明)。例如:
foo|bar*
等效于:
(foo)|(ba(r))
因为操作符的优先级高于串联,并且串联的优先级高于可选(|)。因此,此模式匹配字符串foo或字符串ba后面跟着0个或多个r。要匹配foo或字符串bar的0次或多次重复,使用:
foo|(bar)*
为了匹配foo和bar的0次或多次重复序列:
(foo|bar)*
除了字符和字符范围之外,字符类还可以包含字符类表达式。这些表达式包含在'[:'和':]'分隔符中(分隔符本身必须出现在字符类的'['和']'之间,其它元素也可能出现在字符类中)。有效的表达式是:
[:alnum:] [:alpha:] [:blank:]
[:cntrl:] [:digit:] [:graph:]
[:lower:] [:print:] [:punct:]
[:space:] [:upper:] [:xdigit:]
这些表达式都指定了一组等价于相应标准C的XXX函数。例如,'[:alnum:]'等价于isalnum(),它是任何字符或数字时返回true。有些系统不提供isblank(),所以flex将’[:blank:]’定义为空白或制表符。
例如,以下字符类都是等效的:
[[:alnum:]]
[[:alpha:][:digit:]]
[[:alpha:][0-9]]
[a-zA-Z0-9]
警告:当在伸缩输入中看到字符类时,会立即展开。这意味着字符类对执行flex的区域设置敏感,而生成的扫描器对运行时区域设置不敏感。这可能是可取的也可能不是可取的。
如果您的扫描器不分区大小写('-i'标志),那么'[:upper:]'和'[:lower:]'相当于'[:alpha:]'。
如果范围跨越大写或小写字符,则应在不分区大小写的扫描程序中谨慎使用具有范围的字符类,例如'[a-z]'。flex不知道是要将所有大写和小写字符折叠在一起,还是要指定文字数字范围(没有大小写折叠)。如果有疑问,flex将假定您指的是字面数字范围,并发出警告。此规则的例外是字符范围,如'[a-z]'或'[S-W]',在这些字符范围中,您显然希望发生大小写折叠。以下是启用'-i'标志的一些示例:
Range | Result | Literal Range | Alternate Range |
---|---|---|---|
'[a-t]' | ok | '[a-tA-T]' | |
'[A-T]' | ok | '[a-tA-T]' | |
'[A-t]' | ambiguous | '[A-Z[\]_`a-t]' | '[a-tA-T]' |
'[_-{]' | ambiguous | '[_`a-z{]' | '[_`a-zA-Z{]' |
'[@-C]' | ambiguous | '[@ABC]' | '[@A-Z[\]_`abc]' |
像上面的示例'[A-Z]'这样的反字符类将匹配换行符,除非'\n'(或等效转义序列)是在反字符类中显示出现的字符之一(例如'[A-Z\n]')。这与许多其它正则表达式工具处理否定字符类的方式不同,但不幸的是,这种不一致性在历史上是根深蒂固的。匹配换行符意味着像'[^”]*'这样的模式可以匹配整个输入,除非输入中有另一个引号。 | |||
flex允许通过在POSIX字符类名称前加上'^'来否定字符类表达式。 |
[:^alnum:] [:^alpha:] [:^blank:]
[:^cntrl:] [:^digit:] [:^graph:]
[:^lower:] [:^print:] [:^punct:]
[:^space:] [:^upper:] [:^xdigit:]
如果表达式'[:upper:]'和'[:lower:]'出现在不区分大小写的扫描器中,flex将发出警告,因为它们的含义不清楚。当前的行为是完全跳过它们,但在flex的未来版本中可能会在不通知的情况下改变。
'{-}'运算符计算两个字符类的差值。例如,'[a-c]{-}[b-z]'表示'[a-c]'类中不属于'[b-z]'类的所有字符(在这种情况下,指示单个字符'a')。
'{-}'操作符是左结合的,因此'[abc]{-}[b]{-}[c]'与'[a]'相同。注意不要意外的创建一个空集合,因为它永远不会匹配。
'{+}'运算符计算两个字符类的并集。例如,'[a-z]{+}[0-9]'与'[a-z0-9]'是一样的。当前面有一个差运算的结果时,这个运算符很有用,如'[[:alpha:]]{-}[[:lower:]]{+}[q]',在C语言环境中相当于'[a-zq]'。
一个规则最多只能有一个尾随上下文实例('/'操作符或'$'操作符)。开始条件''和'<<EOF>>'模式只能出现在模式的开头,并且不能将'/'和'$'分组在括号内。没有出现在规则开头的''或没有出现在规则末尾的'$'将失去其特殊属性,并被视为正常字符。
下面是无效的:
foo/bar$
注意,第一个可以写成'foo/bar\n'。
以下命令将导致'$'或'^'被视为正常字符:
foo|(bar$)
foo|^bar
如果所需的含义是'foo'或'bar'后面跟着一个换行符,则可以使用以下操作(特殊的'|'操作将在下面解释,参见操作):
foo |
bar$ /* action goes here */
类似的技巧也适用于匹配'foo'或'bar'在A行开头的字符。