Chinaunix首页 | 论坛 | 博客
  • 博客访问: 242965
  • 博文数量: 52
  • 博客积分: 1355
  • 博客等级: 中尉
  • 技术积分: 485
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-06 12:23
文章分类

全部博文(52)

文章存档

2013年(5)

2012年(16)

2011年(26)

2010年(2)

2009年(1)

2008年(2)

我的朋友

分类: C/C++

2011-08-04 11:36:51

 
操作符(规则组合) R1 + R2

R1 + R2 表示顺序匹配:匹配 R1 成功后继续匹配 R2。编译原理中一般以 R1 R2 表示(很遗憾,C++没有operator空格)。这应该是使用最多的文法了。

例如:要匹配html标签开始,也就是,这样写:'<' + html_symbol() + '>'。

R1 | R2

R1 | R2 表示如果 R1 匹配不成功,则匹配 R2。两者只要一个匹配成功就表示成功。

例如:要匹配C++中的类/结构体声明,也就是:

class/struct ClassName;

我们可以这样写:

(str("class") | str("struct")) + ws() + c_symbol() + skipws() + ';'

这里,ws()表示匹配>=1个空白字符,skipws()表示匹配>=0个空白字符。class/struct关键字和类名之间空白 是必须的,所以用ws(),而类名和;之间空白不是必须的,故而用skipws()。另外,str("class") | str("struct")可以缩写为str("class", "struct"),不过这不是我们要讨论的话题。

+R

+R 表示匹配规则 R 1次以上。编译原理中习惯以 R+ 表示。

例如:要匹配一个无符号整数,我们这样写: +digit()。

当然,对于这个例子,你其实不需要用+,因为我们已经提供了 u_integer() 规则了。

!R

!R 表示匹配规则 R 1次或0次。编译原理中习惯以 R? 表示,不过C++没有operator?,很遗憾。

例如:要匹配一个带符号整数,我们这样写:!(ch('+') | ch('-')) + u_integer()。

同str一样,ch('+') | ch('-') 可缩写为 ch('+', '-')。故此本例可简写为 !ch('+', '-') + u_integer()。

当然,对于这个例子,你其实不需要用!,因为我们已经提供了 integer() 规则了。

*R

*R 表示匹配规则 R 0次以上。编译原理中习惯以 R* 表示。

R1 % R2

R1 % R2 匹配一个列表。它等价于 R1 + *(R2 + R1)。

例如:要匹配一个空格分割的浮点数列表,如“1.2 1.3 2.4 3 23.01",你只需要用 real() % ws() 即可。这里用了 ws(),这就允许中间的空白可以是一个或多个。如果只允许一个空格,那么用 real() % ' ' 即可。

~R

~R 表示匹配一个非R规则的字符。R规则要求是匹配单字符的规则。例如 ~(ch('+') | ch('-')) 表示匹配任一个非+或-的字符。

未完待续。。。

TPL的基础规则 ch(Char)

ch(Char) 规则用于匹配一个字符。例如ch('<')表示匹配单个字符'<'。当 ch(Char) 规则与其他规则连用时,可简写为 Char。

例如,我们前面介绍了匹配html标签开始,也就是,这样写:'<' + html_symbol() + '>'。其实它是 ch('<') + html_symbol() + ch('>') 的缩写。

ch(Char1, Char2), ch(Char1, Char2, Char3)

它只是 ch(Char1) | ch(Char2) 和 ch(Char1) | ch(Char2) | ch(Char3) 的简写。

ch_any()

ch_any() 规则匹配任意一个字符。除非当前已经到达文档结尾,否则该规则总返回成功。

ch_range()

ch_range() 规则表示一个字符区间。如 ch_range<'a', 'z'>() 表示所有小写字母。你可以理解ch_range()为ch(Char)的组合。例如 ch_range<'0', '9'>() 等价于 ch('0') | ch('1') | ch('2') | ch('3') | ch('4') | ch('5') | ch('6') | ch('7') | ch('8') | ch('9')。当然这只是逻辑上的等价,性能后者会差很多。

peek(Char)

peek(Char) 规则用于向前看一个字符(但并不移动匹配的当前指针)。例如peek('<')表示要求文档当前位置的字符必须为'<'。

peek(CharSet), peek(Char1, Char2), peek(Char1, Char2, Char3)

peek规则也允许传入任意的匹配单字符的规则。例如,peek(~ch('+', '-')) 要求文档当前位置的字符必须为非'+'或'-'的字符。 peek(Char1, Char2) 是 peek(ch(Char1) | ch(Char2)) 的缩写。peek(Char1, Char2, Char3) 类似。

str(String)

str(String) 规则用于匹配一个常量字符串。你仍然可以理解为是 ch(Char) 的组合。例如 str("class") 等价于 ch('c') + ch('l') + ch('a') + ch('s') + ch('s')。同ch(Char)类似,当str(String)规则与其他规则连用时,可简写为 String。

find(CharSet)

find(CharSet) 规则用于查找头一个存在于CharSet中的字符。如果bEat为true,那么find规则同时匹配该字符(匹配的当前位置将指向该字符的后一个位 置)。如果bEat为false,那么find匹配到该字符所在位置。默认bEat=false。也就是说find(CharSet)等价于 find(CharSet)。

find规则同样可以用ch规则实现。例如,find(ch('+', '-')) 等价于 *~ch('+', '-') + ch('+', '-')。不过 find(ch('+', '-')) 与 *~ch('+', '-') 并不等同,区别在于如果找不到'+'或'-'字符,find(ch('+', '-')) 将匹配失败,而 *~ch('+', '-') 将匹配到文档尾并匹配成功。所以需要注意的是,find(ch('+', '-')) 等同于 *~ch('+', '-') + peek('+', '-'),不是 *~ch('+', '-')。

find(String)

find(String) 规则用于在文档中查找字符串的第一次出现位置(从当前匹配位置开始算)。例如,要匹配C语言的注释/* … */,你可以用 "/*' + find("*/")。

规则的组合

以上介绍的ch, peek, str, find操作是TPL的基础规则。有了他们,你可以做出非常复杂的匹配模式。这里举一些例子进行说明。

integer()

匹配一个整数。它等价于: !ch('+', '-') + (+ch_range<'0', '9'>())。

c_symbol()

匹配一个C符号(变量名)。它等价于:(ch_range<'a', 'z'>() | ch_range<'A', 'Z'>() | '_') + *(ch_range<'a', 'z'>() | ch_range<'A', 'Z'>() | ch_range<'0', '9'>() | '_')。

其他

我们提供了很多很多的现成的规则,而且它们确确实实是这些基础规则的组合得到的,而不是通过实现一个自定义的匹配函数完成。虽然所有的匹配规则你都可以通过写匹配函数完成,但是那样的话就放弃了TPL最强悍的武器了。

目前已经提供的组合规则如下(不断更新中):

匹配单字符的规则
non_eol_space() 匹配一个非行结束的空白字符。
space() 匹配一个空白字符。
alpha() 匹配一个字母。即[A-Za-z]。
lower() 匹配一个小写字母。即[a-z]。
upper() 匹配一个大写字母。即[A-Z]。
digit() 匹配一个10进制数字。即[0-9]。
xdigit() 匹配一个16进制数字。即[0-9a-fA-F]。
oct_digit() 匹配一个8进制数字。即[0-7]。
bin_digit() 匹配一个2进制数字。即[01]。
匹配多字符的规则
ws() 匹配>=1个空白字符。
skipws() 匹配>=0个空白字符。
non_eol_ws() 匹配>=1个非行结束的空白字符。
skip_non_eol_ws() 匹配>=0个非行结束的空白字符。
strict_eol() 匹配一个行结束。行结束不一定是单字符的。可以是/r/n, /r, /n等情况。
eol() 匹配一个行结束或文档结束。即 strict_eol() | eos()。
xml_symbol() 匹配一个XML的符号。
u_integer() 匹配一个无符号整数。
hex_integer() 匹配一个16进制无符号整数。注意,它并不匹配C/C++中的16进制数0xXXXX的前缀0x。如果你希望这样,应该用c_hex_integer() 而不是 hex_integer()。
oct_integer() 匹配一个8进制无符号整数。
bin_integer() 匹配一个2进制无符号整数。
integer() 匹配一个有符号整数。
u_strict_real() 匹配一个无符号的实数/浮点数。该实数是严格的浮点数,不能是整数。
strict_real() 匹配一个有符号的实数/浮点数。该实数是严格的浮点数,不能是整数。
u_real() 匹配一个无符号的实数/浮点数。即 u_strict_real() | u_integer()。
real() 匹配一个有符号的实数/浮点数。即 strict_real() | integer()。
t_year() 匹配年份。即yyyy或者yy。其中y是[0-9]。
t_month() 匹配月份。即mm或者m。其中m是[0-9]。目前我们并不限定其取值范围必须为1~12。但不排除以后可能会这样去限制。
t_day() 匹配天。
t_hour() 匹配小时。
t_minute() 匹配分钟。
t_second() 匹配秒。
C/C++文法
c_symbol() 匹配一个C/C++的符号。即 [A-Za-z_][A-Za-z0-9_]*。
cpp_single_line_comment() 匹配C++的//风格的注释。bEatEol为true时匹配行结束符,否则保留行结束符。和前面的find规则类似,默认bEatEol为false。
c_comment() 匹配C的/* … */风格的注释。
cpp_comment() 匹配C/C++的注释。即c_comment() | cpp_single_line_comment()。
c_skip() 忽略空白或C风格注释。即 *(ws() | c_comment())。
c_skip_non_eol() 忽略非行结束的空白字符或注释。即 *(non_eol_ws() | c_comment())。该规则适合于C预处理指令的匹配。
cpp_skip() 忽略空白或C/C++注释。即 *(ws() | cpp_comment()。
c_string() 匹配C/C++的字符串常量。即 "…"。注意并不包括L"…"中的L。
c_char() 匹配C/C++的字符常量。即 '…'。注意并不包括 L'…'中的L。
c_string_or_char() 即c_string() | c_char()。
c_hex_integer() C/C++中的16进制数常量。即0xXXXX。注意并不包括0xXXXXL中的L。
c_oct_integer() C/C++中的8进制数常量。即0XXXX。注意并不包括0XXXXL中的L。
c_u_integer() C/C++中的无符号整数。即 c_hex_integer() | c_oct_integer() | u_integer()。
c_integer() C/C++中的带符号整数。即 c_hex_integer() | c_oct_integer() | integer()。
HTML文法
html_space() 匹配一个HTML中的空白字符。
html_ws() 即+html_space()。
html_skipws() 即*html_space()。
html_symbol() 匹配一个HTML的符号。
html_value() 匹配HTML的属性值。
html_property() 匹配HTML的属性。包括名和值的对。注意值是可选的,HTML中可能出现一个属性有名无值。如
这样的标签。
html_u_integer() 匹配HTML的无符号整数。即#xXXXX(16进制)或者 #XXXX(10进制)。
html_entity() 匹配HTML的一个实体。如<   等命名实体。注意它也可以匹配非命名的实体。如? 等。
html_comment() 匹配一个HTML的注释。即 >。
html_uncommented_script_code() 未被注释的script代码。
html_commented_script_code() 注释的script代码。注意不包含注释开始和结尾>。
html_script_code() 匹配一个HTML的script段。即:html_uncommented_script_code() | "" + html_commented_script_code() + ">"。
html_script_codes() 匹配多个HTML的script段。即 *html_script_code()。

关于 html script code。有些复杂的东西需要解释。看这样一段HTML代码:

<script> var hello="Hello, <script>!"; alert(hello); !'; alert(hello); --> script>

这里包含了两段html script code。一段是未注释的,一段是被注释的。要匹配这段文本,可以用""。注意我们用的是html_script_codes(),不是html_script_code()。也就是说,

阅读(838) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~