您的位置:首页 > 其它

正则表达式

2007-04-04 16:10 141 查看
>>正则表达式语法

1. 匹配字符
大多数字符与其本身匹配. 下列模式匹配一个a和一个跟在后面的b:

ab

普通通配符是一个点(.), 它匹配任意一个字符. 下列模式匹配一个a和一个跟在后面的任意字符:

a.

要记住, 字符匹配可能发生在字符串中的任何位置, 一个模式不必匹配整个字符串. 你可以通过使用挂靠符(anchor)来改变匹配方式.

2. 字符集合
通过使用[xyz]这样的语法, 可以将进行匹配的字符限制在一组字符中. 这两个方括号之间的任意字符都允许匹配. 例如,
下列表达式要么匹配Hello, 要么匹配hello:

[Hh]ello

可以使用语法[x-y]来将进行匹配的集合指定为字符集的某个区间. 下列表达式匹配任意数字:

[0-9]

我们还可以指定一个集合的补集, 也就是说, 匹配字符可以是除该集合以外的任意字符. 我们使用语法[^xyz]来指定这个集合的补集.
区间与集合的补集可以组合起来使用. 下列表达式可以匹配除大小写字母和小写字母之外的所有字符:

[^a-zA-Z]

=>在字符集中使用特殊字符
你如果想在字符集中包括一个], 就要将它放在紧跟起始方括号之后的位置. 要在字符集中包括[, 则无须做任何特殊工作.
下列表达式匹配任意方括号和花括号:

[][{}]

大多数正则表达式的语法字符在处于字符集当中时就不再具有特殊意义. 这意味着在你使用方括号括起来的字符集中无须使用任何反斜杠引用,
反斜杠自身除外. 下列表达式匹配正则表达式中用到的若干语法字符:

[][+*?()|//]

高级正则表达式(ARE)增加了名字和反斜杠换码序列来作为诸如空白符, 字母, 字母数字等等常用字符集的简单记号.

3. 量词
使用*表示重复零次或多次, +表示重复一次或多次, 而?表示重复零次或一次. 这些量词作用于前面的条目, 而这些条目可以是一个匹配字符,
字符集或是一个用圆括号括起来的子模式. 下列表达式匹配一个包含b并在后面跟有零个或多个字符a的字符串:

ba*

可以使用圆括号将部分模式括起来, 然后用一个量词来作用于那部分模式. 下列表达式匹配具有一个或多个ab序列的字符串:

(ab)+

匹配任意字符串甚至是空字符串的模式为:

.*

这些量词具有贪婪的(greedy)匹配行为: 它们尽可能多地匹配字符. 高级正则表达式增加了非贪婪(nongreedy)匹配. 例如,
匹配单行信息的表达式看起来就像下面这个样子:

.*/n

然而, 如果是贪婪匹配的话, 它将会匹配所有输入行, 并在输入字符串中的最后一个换行符上终止. 下列表达式一直匹配到第一个换行符:

[^/n]*/n

我们将会使用非贪婪量词来进一步简化这个模式, 随后还将描述一些可以用来打开特殊的换行符敏感模式的选项.

4. 交替匹配(Alternation)
交替匹配可以同时测试不止一个模式. 匹配引擎被设计成能够并行测试多个模式, 因此交替匹配是高效的.
Tcl使用管道符|来指定交替匹配, 另外一种匹配Hello或hello的方式就是:

hello|Hello

还可以这样写:

(h|H)ello

或者是:

[hH]ello

5. 匹配挂靠
在默认情况下, 一个模式不必匹配整个字符串. 在匹配的前面或者后面都可以有未匹配的字符.
你可以通过在模式前使用^来使匹配挂靠在字符串的起始位置, 或是在模式结尾处使用$来让其挂靠在字符串的末尾.
你可以同时使用两种方式来匹配整个字符串. 可以使用下列表达式来匹配所有以空格或制表符开始的字符串:

^[ /t]+

如果你的输入中包含有许多文本行, 你或许会以为^表示"行起始"而不是"字符串起始". 默认情况下,
定位符^和$是相对整个输入来说的, 而忽略内嵌的换行符. 高级正则表达式支持将定位符^和$设置为面向行的选项,
而且还增加了挂靠符/A和/Z, 它们总是分别匹配字符串的起始与终止位置.

6.反斜杠引用
使用反斜杠字符来关闭这些字符的特殊意义:

. * ? + [ ] ( ) ^ $ | /

例如, 要匹配字符加号, 你需要使用:

/+

要记住, 这种引用在由方括号括起来的表达式(即字符集定义)内部是不必要的. 例如, 要匹配加号或问号, 这两种模式都可以工作:

(/+|/?)
[+?]

要匹配单个反斜杠, 就需要使用两个反斜杠. 在任何地方都要这么做, 即便是在方括号括起来的表达式中也是如此.
或者你也可以使用/B, 它是高级正则表达式中新增的. 这两个表达式均匹配一个单一的反斜杠:

//
/B

7. 匹配优先级
如果一个模式可以匹配一个字符串的多个部分, 那么匹配器就会与输入字符串中最早出现的部分进行匹配. 然后,
如果由于模式中交替匹配的原因, 在相同的地点还有不止一处匹配的话, 匹配器就会尽可能匹配最长的那个.
法则就是: 先是最早的, 然后是最长的. 使用执行较短匹配的非贪婪量词就可以改变这种规则.

大家小心*, 它表示零个或多个, 因为零个什么东西很容易就能匹配成功. 假设你的模式为:

[a-z]*

用这个模式与123abc进行匹配, 但是结果并不是你所期望的那样. 这个模式不是匹配字符串中的字母,
而是匹配位于输入字符串最前端的长度为零的子串. 我们可以使用regexp命令的-indices选项来检测这种行为,
该选项将告诉你匹配字符串的位置而不是匹配字符串的值.

8. 捕获子模式
使用圆括号来捕获子模式. 与圆括号中的模式匹配的字符串会被记录在匹配变量中,
匹配变量是一个被赋值为与模式匹配的字符串的Tcl变量. 使用圆括号来捕获子模式非常有用.
假设我们要获取HTML中位于标签和之间的所有内容, 就可以使用下面这种模式:

([^<]*)匹配变量就会被赋值为输入字符串中与圆括号中的模式相匹配的那部分内容. 你可以在一次匹配中捕获许多的子模式,
这是一种非常高效的选择数据的方式.

有时你需要引入圆括号但又不需要了解其中发生的匹配情况, 如果匹配器无须记忆匹配的话, 模式的效率就会稍微高一些.
高级正则表达式通过下面语法增加了非捕获圆括号:

(?:pattern)

>>高级正则表达式(ARE)

1. 反斜杠换码序列
高级正则表达式语法中最为显著的变化就是反斜杠替换. 在Tcl8.0及以前的版本中, 反斜杠只是被用来关闭一些特殊字符的意义,
如: ., +, *, ?, [], 对于其他情况则是忽略不管的. 例如, /n对于Tcl8.0的正则表达式引擎来说只是一个n,
这是一个令人迷惑的地方, 而且它还意味着并不总是能够通过花括号将模式括起来使这些特殊字符逃避Tcl语法分析器的解析.
在高级正则表达式中, /n现在对正则表达式引擎来说表示换行符, 于是你不再需要让Tcl来完成反斜杠处理工作了.

高级正则表达式增加了大量新的反斜杠序列. 其中一些较为有用的包括/s(匹配空格之类的内容), /w(匹配字母, 数字和下划线),
/y(匹配单词的起始和终止位置)以及/B(匹配一个反斜杠).

2. 字符类(character class)
字符类为各种字符集合的名称. 有名字符类语法只有出现在用方括号括起来的字符集中才有效. 语法为:

[:标识符:]

例如, alpha是包含大写与小写字母的集合的名字, 下面两个模式几乎是相同的:

[A-Za-z]
[[:alpha:]]

区别就在于alpha字符类还包含重音字符, 如è. 如果你要匹配包含非ASCII字符的数据, 那么这种有名字符类就比明确指定这些字符更为通用.

其中的一些有名字符类拥有反斜杠序列的简化形式. 下列匹配数字的模式是等价的:

[0-9]
[[:digit:]]
/d

下列模式匹配诸如退格符, 换页符, 换行符, 回车, 制表符以及垂直制表符等类似空白符的字符:

[ /b/f/b/r/t/v]
[:space:]
/s

你可以在一个字符集定义中将字符类与其他字符类组合在一起使用. 下列模式匹配字母, 数字和下划线:

[[:digit:][:alpha:]_]
[/d[:alpha:]_]
[[:alnum:]_]
/w

注意, /d, /s与/w既可以在字符集内也可以在字符集外使用. 当在用方括号括起来的表达式以外使用时,
它们就形成自己的字符集. 还有作为/d, /s和/w补充的/D, /S和/W. 这些换码(即/D表示非数字)不能在用方括号括起来的字符集内使用.

有两个特殊的字符类, [[:<:]和[[:>:]], 它们分别匹配单词的起始和终止位置, 单词被定义为一个或多个匹配/w的字符.

3. 非贪婪量词
字符*, +和?是指定重复次数的量词. 在默认情况下, 这些字符尽可能多地匹配字符, 这被称之为贪婪匹配.
非贪婪匹配则是尽可能少地匹配字符. 你可以通过在这些量词后面放置一个问号来指定为非贪婪匹配.
考虑下面匹配"一个或多个后面跟有一个换行符的非换行符"的模式. 在使用贪婪量词时, 必须明确指定这种非换行符, 如:

[^/n]+/n

否则, 如果模式仅为

.+/n

那么"."随即就会匹配换行符, 于是该模式将会贪婪地耗尽输入中的所有内容直到最后一个换行符为止. 而非贪婪匹配碰到第一个换行符就满足了:

.+?/n

通过使用非贪婪量词, 我们将模式从8个字符缩减为5个. 下列模式匹配也可以匹配与之间的所有内容:

(.*?)我们甚至可以将?也变成非贪婪的, ??表示它更倾向于零个而不是一个. 这种情况在一些较大模式的上下文中才有意义.

4. 约束量词
语法{m, n}是一个量词, 它表示前面的匹配项至少匹配m次, 至多匹配n次. 该语法有两个变种.
简单的{m}表示前面的匹配项要确切地匹配m次. {m, }表示前面的匹配项要匹配m或更多次. 所有这些量词都可以在后面加上一个?来变成非贪婪的.

5. 回退引用
回退引用是一项使用基本正则表达式不容易实现的功能. 回退引用匹配用圆括号捕获的子模式的值.
你如果有多组圆括号, 那么就可以回过头来使用/1, /2等等来指代各个被捕获的表达式. 你可以通过清点左括号来判定相应的引用.

例如, 假设你要匹配一个用单引号或双引号括起来的字符串, 你需要使用一个包含两种模式的交替匹配来匹配用双引号或单引号括起来的字符串:

("[^"]*"|'[^']*')

如果使用回退引号, /1, 该模式就可以更简单一些:

('|").*?/1

第一组圆括号匹配起始的引号, 然后/1又回头引用那个特定的引用字符. 非贪婪量词确保了模式匹配到第一个匹配引号的出现为止.

5. 前瞻(look-ahead)
前瞻模式是一些进行匹配但不消耗任何输入的子表达式. 它们的行为就像对剩余模式的约束,
而且通常出现在模式的结尾. 肯定的(positive)前瞻如果匹配的话就会使模式也匹配, 否定的(negative)前瞻在它不匹配的情况下使模式匹配.
这些约束在匹配变量和使用regsub命令来完成的正则表达式替换的上下文中才会更有意义. 例如, 下面的模式匹配以A开头并以.txt结尾的文件名:

^A.*/.txt$

下一个版本的模式使用圆括号来将文件名后缀括起来:

^A.*(/.txt)$

严格来说, 圆括号是不必要的, 但是引入它们是为了将该模式与使用前瞻的内容进行比较. 一个使用前瞻模式的版本如下所示:

^A.*(?=/.txt)$

带有前瞻约束的模式只在.txt存在的情况下, 才会匹配.txt之前的那部分文件名, 换句话说就是匹配不会消耗掉.txt.
这可以从regexp命令所使用的匹配变量值中看出来. 它还会影响regsub命令中所完成的替换操作.

Tcl中还有否定的前瞻. 下面的模式匹配以A开头但不以.txt结尾的文件名:

^A.*(?!/.txt)$

如果没有否定前瞻, 编写这种模式就会很烦琐.

6. 文字编码
语法/nn和/mmm(其中的n和m为数字)还可以表示与八进制数值nn或mmm对应的8位字符编码.
这种语法的优先级别高于反斜杠引用. 不过我可不会使用这种记号来表示字符编码, 我使用Unicode换码序列/unnnn,
它指定了一个16位的值, /xnn序列同样也指定一个8位字符编码. 不幸的是,
换码序列/x会消化掉跟在后面所有十六进制数字(而不仅仅是两个数字), 然后将十六进制数值截短至8位.
但/x的这个毛病并不被认为是个bug, 甚至在未来版本的Tcl中也不大可能改变.

语法/Uyyyyyyyy被保留给32位的Unicode. 但是我估计它不大可能很快会被实现.

7. 归整元素(collating element)
归整元素是一些能够在字符串中使用的字符或字符的长名称. 当前, 只有Tcl中的各种ASCII标点字符才有长名称.
Tcl潜在可以支持所有的Unicode字符的名称, 但是由于这样会使映射表非常巨大, 所以它一般地并不支持.

在用方括号括起来的表达式中使用下面的语法来指定一个归整元素:

[.标识符.]

标识符可以是一个字符或一个长名称. 下面是几个例子:

[.c.]
[.#.]
[.number-sign.]

8. 等价类(equivalence class)
等价类就是排序时位于相同位置的所有字符. 这是当前版本的Tcl中另一项用途有限的功能. 在Tcl中,
字符按照它们的Unicode字符值进行排序, 因此不会存在包含多于一个字符的等价类!
不过你可以为"o"或"ò"以及其他口音的字母o假设一个字符类. 等价类在方括号中括起来的表达式的语法为:

[=char=]

这里char是字符类中的一个字符. 该语法只有在字符类中定义才在字符类定义中才有效.

9. 换行符敏感的匹配
在默认情况下, 换行符对匹配引擎来说只是一个普通的字符. 你可以使用选项lineanchor和linestop来使换行符具有特殊意义.
通过Tcl命令regexp和regsub的标志可以设置这些选项.

lineanchor选项使得挂靠符^和$相对换行符来工作. ^匹配紧跟换行符之后的位置, 而$匹配紧贴换行符之前的位置.
这些定位符还可以继续匹配输入的开头和结尾. 无论有没有lineanchor选项, 你都可以使用/A和/Z来匹配字符串中的起始和结尾位置.

linestop选项阻止和以^开头的字符集合匹配换行符. 换言之, 除非你在模式中明确包括了/n, 否则它是不会匹配换行符的.

10. 嵌入式选项
你可以用嵌入式选项作为一个模式的开头来打开或关闭大小写敏感, 换行符敏感以及扩展语法,
你也可以从高级正则表达式切换到纯粹的字符串或是较老形式的正则表达式. 这种语法为一个前导的:

(?chars)

这里chars是任意个数的选项字符.

11. 扩展语法
扩展语法允许在模式中包含注释或额外的空白符. 它可以极大地提高复杂模式的可读性.
可以使用regexp命令选项或嵌入式选项来打开扩展语法功能.

注释将以#开头并一直延伸到结尾. 额外的空白符和注释可以出现在除用方括号括起来的表达式(即字符集)
或多字符语法元素中----如(?=----以外的任意地方. 当处于扩展模式中时,
你可以通过在它们的前面加上一个反斜杠来关闭注释字符或明确包含一个空格符. 例如:

regexp {(?x) #A pattern to match URLS
([^:]+): #The protocol before the initial colon
//([^:/]+) #The server name
(:([0-9]+))? #The optional port number
(/.*) #The trailine pathname
} $input
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: