一个正则表达式就是由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)组成的文字模式。该模式描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。 \ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 后向引用、或一个八进制转义符。例如,'n' 匹配字符 "n"。'\n' 匹配一个换行符。序列 '\\' 匹配 "\" 而 "\(" 则匹配 "("。 ^ 匹配输入字符串的开始位置。 $ 匹配输入字符串的结束位置。 * 匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。 * 等价于{0,}。 + 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。 ?
作者:吕**
出处:不详
如果我们问那些UNIX系统 的爱好者他们最喜欢什么,答案除了稳定的系统和可以远程启动之外,十有八九的人会提到正则表达式;如果我们再问他们最头痛的是什么,可能除了复杂的进程控制和安装过程之外,还会是正则表达式。那么正则表达式到底是什么?如何才能真正的掌握正则表达式并正确的加以灵活运用?本文将就此展开介绍,希望能够对那些渴望了解和掌握正则表达式的读者有所助益。
入门简介
简单的说,正则表达式是一种可以用于模式 匹配和替换的强有力的工具。我们可以在几乎所有的基于UNIX系统的工具中找到正则表达式的身影,例如,vi编辑器,Perl或PHP脚本语言,以及awk或sed shell 程序等。此外,象JavaScript这种客户端的脚本语言也提供了对正则表达式的支持。由此可见,正则表达式已经超出了某种语言或某个系统的局限,成为人们广为接受的概念和功能。
正则表达式可以让用户通过使用一系列的特殊字符构建匹配模式,然后把匹配模式与数据 文件、程序输入以及WEB页面的表单输入等目标对象进行比较,根据比较对象中是否包含匹配模式,执行相应的程序。
举例来说,正则表达式的一个最为普遍的应用 就是用于验证用户在线输入的邮件地址的格式是否正确。如果通过正则表达式验证用户邮件地址的格式正确,用户所填写的表单信息将会被正常处理;反之,如果用户输入的邮件地址与正则表达的模式不匹配,将会弹出提示信息,要求用户重新输入正确的邮件地址。由此可见正则表达式在WEB应用的逻辑判断中具有举足轻重的作用。
基本语法
在对正则表达式的功能和作用有了初步的了解之后,我们就来具体看一下正则表达式的语法格式。
正则表达式的形式一般如下:
/love/
其中位于“/”定界符之间的部分就是将要在目标对象中进行匹配的模式。用户只要把希望查找匹配对象的模式内容放入“/”定界符之间即可。为了能够使用户更加灵活的定制模式内容,正则表达式提供了专门的“元字符”。所谓元字符就是指那些在正则表达式中具有特殊意义的专用字符,可以用来规定其前导字符(即位于元字符前面的字符)在目标对象中的出现模式。
较为常用的元字符包括: “+”, “*”,以及 “?”。其中,“+”元字符规定其前导字符必须在目标对象中连续出现一次或多次,“*”元字符规定其前导字符必须在目标对象中出现零次或连续多次,而“?”元字符规定其前导对象必须在目标对象中连续出现零次或一次。
下面,就让我们来看一下正则表达式元字符的具体应用。
/fo+/
因为上述正则表达式中包含“+”元字符,表示可以与目标对象中的 “fool”, “fo”, 或者 “football”等在字母f后面连续出现一个或多个字母o的字符串相匹配。
/eg*/
因为上述正则表达式中包含“*”元字符,表示可以与目标对象中的 “easy”, “ego”, 或者 “egg”等在字母e后面连续出现零个或多个字母g的字符串相匹配。
/Wil?/
因为上述正则表达式中包含“?”元字符,表示可以与目标对象中的 “Win”, 或者 “Wilson”,等在字母i后面连续出现零个或一个字母l的字符串相匹配。
除了元字符之外,用户还可以精确指定模式在匹配对象中出现的频率。例如,
/jim/
上述正则表达式规定字符m可以在匹配对象中连续出现2-6次,因此,上述正则表达式可以同jimmy或jimmmmmy等字符串相匹配。
在对如何使用正则表达式有了初步了解之后,我们来看一下其它几个重要的元字符的使用方式。
\s:用于匹配单个空格符,包括tab键和换行符;
\S:用于匹配除单个空格符之外的所有字符;
\d:用于匹配从0到9的数字;
\w:用于匹配字母,数字或下划线字符;
\W:用于匹配所有与\w不匹配的字符;
. :用于匹配除换行符之外的所有字符。
(说明:我们可以把\s和\S以及\w和\W看作互为逆运算)
下面,我们就通过实例看一下如何在正则表达式中使用上述元字符。
/\s+/
上述正则表达式可以用于匹配目标对象中的一个或多个空格字符。
/\d000/
如果我们手中有一份复杂的财务报表,那么我们可以通过上述正则表达式轻而易举的查找到所有总额达千元的款项。
除了我们以上所介绍的元字符之外,正则表达式中还具有另外一种较为独特的专用字符,即定位符。定位符用于规定匹配模式在目标对象中的出现位置。
较为常用的定位符包括: “^”, “$”, “\b” 以及 “\B”。其中,“^”定位符规定匹配模式必须出现在目标字符串的开头,“$”定位符规定匹配模式必须出现在目标对象的结尾,\b定位符规定匹配模式必须出现在目标字符串的开头或结尾的两个边界之一,而“\B”定位符则规定匹配对象必须位于目标字符串的开头和结尾两个边界之内,即匹配对象既不能作为目标字符串的开头,也不能作为目标字符串的结尾。同样,我们也可以把“^”和“$”以及“\b”和“\B”看作是互为逆运算的两组定位符。举例来说:
/^hell/
因为上述正则表达式中包含“^”定位符,所以可以与目标对象中以 “hell”, “hello”或 “hellhound”开头的字符串相匹配。
/ar$/
因为上述正则表达式中包含“$”定位符,所以可以与目标对象中以 “car”, “bar”或 “ar” 结尾的字符串相匹配。
/\bbom/
因为上述正则表达式模式以“\b”定位符开头,所以可以与目标对象中以 “bomb”, 或 “bom”开头的字符串相匹配。
/man\b/
因为上述正则表达式模式以“\b”定位符结尾,所以可以与目标对象中以 “human”, “woman”或 “man”结尾的字符串相匹配。
为了能够方便用户更加灵活的设定匹配模式,正则表达式允许使用者在匹配模式中指定某一个范围而不局限于具体的字符。例如:
/[A-Z]/
上述正则表达式将会与从A到Z范围内任何一个大写字母相匹配。
/[a-z]/
上述正则表达式将会与从a到z范围内任何一个小写字母相匹配。
/[0-9]/
上述正则表达式将会与从0到9范围内任何一个数字相匹配。
/([a-z][A-Z][0-9])+/
上述正则表达式将会与任何由字母和数字组成的字符串,如 “aB0” 等相匹配。这里需要提醒用户注意的一点就是可以在正则表达式中使用 “()” 把字符串组合在一起。“()”符号包含的内容必须同时出现在目标对象中。因此,上述正则表达式将无法与诸如 “abc”等的字符串匹配,因为“abc”中的最后一个字符为字母而非数字。
如果我们希望在正则表达式中实现类似编程逻辑中的“或”运算,在多个不同的模式中任选一个进行匹配的话,可以使用管道符 “|”。例如:
/to|too|2/
上述正则表达式将会与目标对象中的 “to”, “too”, 或 “2” 相匹配。
正则表达式中还有一个较为常用的运算符,即否定符 “[^]”。与我们前文所介绍的定位符 “^” 不同,否定符 “[^]”规定目标对象中不能存在模式中所规定的字符串。例如:
/[^A-C]/
上述字符串将会与目标对象中除A,B,和C之外的任何字符相匹配。一般来说,当“^”出现在 “[]”内时就被视做否定运算符;而当“^”位于“[]”之外,或没有“[]”时,则应当被视做定位符。
最后,当用户需要在正则表达式的模式中加入元字符,并查找其匹配对象时,可以使用转义符“\”。例如:
/Th\*/
上述正则表达式将会与目标对象中的“Th*”而非“The”等相匹配。
使用实例
在对正则表达式有了较为全面的了解之后,我们就来看一下如何在Perl,PHP,以及JavaScript中使用正则表达式。
通常,Perl中正则表达式的使用格式如下:
operator / regular-expression / string-to-replace / modifiers
运算符一项可以是m或s,分别代表匹配运算和替换运算。
其中,正则表达式一项是将要进行匹配或替换操作的模式,可以由任意字符,元字符,或定位符等组成。替换字符串一项是使用s运算符时,对查找到的模式匹配对象进行替换的字符串。最后的参数项用来控制不同的匹配或替换方式。例如:
s/geed/good/
将会在目标对象中查找第一个出现的geed字串,并将其替换为good。如果我们希望在目标对象的全局范围内执行多次查找—替换操作的话,可以使用参数 “g”,即s/love/lust/g。
此外,如果我们不需要限制匹配的大小写形式的话,可以使用参数 “i ”。例如,
m/JewEL/i
上述正则表达式将会与目标对象中的jewel,Jewel,或JEWEL相匹配。
在Perl中,使用专门的运算符“=~”指定正则表达式的匹配对象。例如:
$flag =~ s/abc/ABC/
上述正则表达式将会把变量$flag中的字串abc替换为ABC。
下面,我们就在Perl程序中加入正则表达式,验证用户邮件地址格式的有效性。代码如下:
--------------------------------------------------------
#!/usr/bin/perl
# get input
print “What's your email address?\n”;
$email =
chomp($email);
# match and display result
if($email =~ /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/)
{
print(“Your email address is correct!\n”);
}
else
{
print(“Please try again!\n”);
}
--------------------------------------------------------
如果用户更偏爱PHP的话,可以使用ereg()函数进行模式匹配操作。ereg()函数的使用格式如下:
ereg(pattern, string)
其中,pattern代表正则表达式的模式,而string则是执行查找替换操作的目标对象。同样是验证邮件地址,使用PHP编写的程序代码如下:
--------------------------------------------------------
php
if (ereg(“^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+”,$email))
{ echo “Your email address is correct!”;}
else
{ echo “Please try again!”;}
?>
--------------------------------------------------------
最后,我们在来看一下JavaScript。JavaScript 1.2中带有一个功能强大的RegExp()对象,可以用来进行正则表达式的匹配操作。其中的test()方法可以检验目标对象中是否包含匹配模式,并相应的返回true或false。
我们可以使用JavaScript编写以下脚本,验证用户输入的邮件地址的有效性。
--------------------------------------------------------
匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。 {n} n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。 {n,} n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。 {n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。 "o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。 ? 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。 . 匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。 (pattern) 匹配pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在Visual Basic Scripting Edition 中则使用 $0…$9 属性。要匹配圆括号字符,请使用 '\(' 或 '\)'。 (?:pattern) 匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。 (?=pattern) 正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如, 'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 (?!pattern) 负向预查,在任何不匹配Negative lookahead matches the search string at any point where a string not matching pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始 x|y 匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配 "zood" 或 "food"。 [xyz] 字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。 [^xyz] 负值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中的'p'。 [a-z] 字符范围。匹配指定范围内的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z' 范围内的任意小写字母字符。 [^a-z] 负值字符范围。匹配任何不在指定范围内的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到 'z' 范围内的任意字符。 \b 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 \B 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 \cx 匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。 x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。 \d 匹配一个数字字符。等价于 [0-9]。 \D 匹配一个非数字字符。等价于 [^0-9]。 \f 匹配一个换页符。等价于 \x0c 和 \cL。 \n 匹配一个换行符。等价于 \x0a 和 \cJ。 \r 匹配一个回车符。等价于 \x0d 和 \cM。 \s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。 \S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 \t 匹配一个制表符。等价于 \x09 和 \cI。 \v 匹配一个垂直制表符。等价于 \x0b 和 \cK。 \w 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。 \W 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。 \xn 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如, '\x41' 匹配 "A"。'\x041' 则等价于 '\x04' & "1"。正则表达式中可以使用 ASCII 编码。. \num 匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,'(.)\1' 匹配两个连续的相同字符。 \n 标识一个八进制转义值或一个后向引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为后向引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。 \nm 标识一个八进制转义值或一个后向引用。如果 \nm 之前至少有is preceded by at least nm 个获取得子表达式,则 nm 为后向引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的后向引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。 \nml 如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。 \un 匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (?)。
Regular Expression 简介 中央研究 院计算中心 ASPAC 计划 aspac@phi.sinica.edu.tw技术 报告: 94019 1995 年 2 月 9 日 Version : 1.0 版权声明 目录 Why Regular Expression 组成 Regular Expression 的元素 使用 Regular Expression 时的注意事项 范 例 Appendix : Test using Regular Expression in various environments HP-UX Sun Solaris 2.X AIX 3.2.5 GNU Tools Why Regular Expression Regular Expression 是一种字符串表达的方式. 使用者可使用一个简短的 Regular Expression 来表示 〝具有某特征〞 或者 〝复杂难以描述〞的所有字符串. 而日常数据 处理中, 最常进行的工作是『从档案中找出具有某特征的字符串, 再加以处理(打印,置换, 计算...)』. 此时, Regular Expression 便可派上用场. 使用一个简短的 Regular Expression 便可完全指定需要加以处理的资料 , 避免反复判断找寻的困扰. 譬如 : 若使用 MS-DOS 中文 字编辑器 edit 的找寻功能, 可来 找出档案中所有的 ``prg1.c''; 但 edit 却无法一次同 时找寻字符串``prg1.c''、``prg2.c'' ... 或 ``prg8.c''; 必需 反复执行八次找寻的动作. 可是在 UNIX 中的 vi , 使用一个 Regular Expression `` prg[0-8]\.c'' 便可同时表示上述八个字符串, 如此一次就可找出指定的所有字符串. 可见 Regular Expression 确实十分便利. 然而, MS-DOS 下许多工具的设计并不支持解读 Regular Expression. 但 UNIX 环境 下除了 vi 外, 还有许多工具都接受 Regular Expression, 如 : grep、sed 、awk、csplit... . 使用这些工具时, 便可应用 Regular Expression 来指定欲找寻的字符串; 并可配合这些工具的其它功能将找寻到的数据进一步地加以处理. Regular Expression 的特色是简短且表达力强. 它所表达的可以是某一特定的字符串, 也可以是具有某一共同特征的"所有"字符串(如上例). Regular Expression 中定义了一组特殊字符, 它们代表着某些特别的意义; 使用者可藉这些特殊字符来表示字符串的下列特征 : 描述组成字符串的元素(components) : 例 如 : Regular Expression ``[Tt]he'' 代表字符串 ``The'' 或 ``the''. 限制字符串出现的位置 : 例 如 : Regular Expression ``^The'' 代表『出现于行首』的字符串 ``The''. 由于 Regular Expression 具有极佳的字符串表示能力. 往后, 读者若能多利用 UNIX 上接受 Regular Expression 的工具, 且灵活应用 Regular Expression; 则可避免撰写程序进行复杂字符串判断(parsing) 的麻烦. 如此, 才能真正发挥各工具的的功能, 减轻数据处理时的负担, 并增加数据处理的效率. -------------------------------------------------------------------------------- Note 1 UNIX中定义了数种字符串表达方式, Regular Expression 及 Extended Regular Expression 是常见的二种. 另一种是使用于Shell命令列, 将参数展开}(expand)成文件名称的"Pattern Matching Notation", 这种表示法与 Regular Expressions 的语法差异较大, 甚至有数项用法相左, 故位未列入本文讨论以免读者混淆. 组成 Regular Expression 的元素 Regular Expression 是由普通字符、及一组具有特殊意义 的字符所构成. 本节主要介绍各种特殊字符所代表的意义及 其用法. 读者学习 时应留心 : 有时, 同一特殊字符, 会因出 现在字符串中不同的位置或连接其它特殊字符, 而有不同的意义. 本文中为有别于一般的字符串, 所有 Regular Expression 都以粗体字体表示, 且加注``Regexp''于其前方. 组成 Regular Expression 的元素及所代表的意义如下 : [普通字符] 除了``.''、``[''、``]''、``*''、``+''、``?''、 ``|''、``^''、``$''、``{''、``}''、``\''、 ``<''、``>''、``(''、``)'' 外之所有字符. 由普通字符所组成的 Regular Expression 其意义与原字符串字面意义相同. 例如 : 普通字符``A''也可当成一个 Regular Expression. Regexp `` A'' 与一般字符``A''代表相同的意义. Regexp `` the'' 与一般字符串``the''代表相同的意义. [ .] Metacharacter 用以代表任意一个字符. 须留心 UNIX Shell 中使用``?''表示任意一个字符, 使用``*''代表任意长 度的字符串(这是另一种称为 ``Pattern Matching Notation'' 的字符串表示法). Regular Expression 中则使用`` .'' 来代表``一个''任意字符(注 意: 并非任意长度的字符串). 而 Regular Expression 中`` *''另有 其它涵意, 并不代表任意长度的字符串. 例如 Regexp `` .'' 可用以代表任意一个字符. 如 ``A''、``1''、``+''、... Regexp `` ...'' 则代表一个由任意3个字符所的字符串. 譬如 ``123''、``abc''、``# 1''、... [ ^] 限制字符串必须出现于行首. (用法见下例) [ $] 限制字符串必须出现于行末. [例如 :] Regexp `` ^The'' 用以表示所有出现于行首的字符串``The''. Regexp `` The$'' 用以表示所有出现于行末的字符串``The''. Regexp `` ^The$'' 则用以表示一个仅含字符串``The''的数据列. Regexp `` ^$'' 表示一个空白的数据列(行首与行尾之间未存在任一字符). [ \] 将特殊字符还原成字面意义的字符. Regular Expression 中 特殊字符 将被解释成特定的意义. 若要表示特殊字符的字面(literal meaning) 意义时, 在 特殊字符之前加上 ``\'' 即可. [例如 :] 使用 Regular Expression 来表示字符串``a.out''时, 不可写成 Regexp `` a.out''. 因为`` .''在 Regular Expression 中是特殊字符, 表示任一字符. 可合乎(match) Regexp `` a.out'' 的字符串将不只 ``a.out'' 一个; 字符串``a2out'',``a3out'', ``aaout''... 都合于 Regexp `` a.out''. 正确的表示法应为 : Regexp `` a\.out'' `` \'' 在 Regular Expression 中的另一个意 义是当成 Escape character. [例如 :] `` \t'' 用以表示 tab. `` \n'' 表示换行符号. [...] 『字符集合』, 用以表示两中括号间 所有的字符当中的任一个. [例如 : ] Regexp `` [123]'' 可用以表示字符 ``1''、``2'' 或 ``3''. Regexp `` [Tt]'' 可用以表示字符 ``T'' 或 ``t''. 所以, Regexp " [Tt]he" 表示字符串 "The" 或 "the". (注意 : 一个字符集合仅代表``一个''字符.) 使用时, 需留心字符集合 [ ] 内不可随意留空白. 例如 : Regexp `` [ Tt ]'' 中括号内有空格符, 故除了可用 以表示字符``T''或``t''", 也可代表一个 `` ''(空格符). - 字符集合中可使用 `` -'' 来指定字符的区间, 其用法如下: Regexp `` [0-9]'' 等于 Regexp `` [0123456789]'' 用以表示任意 "一个" 阿拉伯数字. 同理 Regexp `` [A-Z]'' 用以表示任意 "一个" 大写英文 字母. 但应留心 : Regexp " [0-9a-z]" 并不等于 Regexp " [0-9][a-z]"; 前者表示一个字符(阿拉伯数字或小写英文字母), 后者表示二个字符. Regexp " [-9]" 或 " [9-]" 仅用以代表字符 ``9''或 ``-''. [ [\^{}... ]] 使用 [\^{...]} 产生字符集合的补集(complement set). 其用法如下 : Regexp `` [^M]'' 用以表示除字符``M''外的``一个''任意字符 字符集合 `` [Tt]''表示字符 ``T'' 或 ``t''. 若要指定 ``T'' 或 ``t'' 之外的任一个字符, 可用Regexp `` [^Tt]'' 表示. Regexp `` [^a-zA-Z]''表示英文字母之外的任一个字符. 需留心 `` ^''之位置; `` ^'' 必须紧接于 `` ['' 之后, 才代表字符集合的补集. [例如 :] Regexp `` [0-9^]'' 表示一个阿拉伯数字或字符 `` ^'', 并非代表阿伯数字外的任意字符. * 用以形容其前的字符或字符集合可重复任意次数的特殊字符. `` *'' 形容它前方之字符(或字符集合)可出现 1 次或多次, 或不出现. 例如 : Regexp ``ab*'' 中, `` *'' 形容它前方的字符 ``b'' 可出现 1 次或多次, 或不出现. 所以, Regexp ``ab*'' 可表示字符串 ``a''、``ab''、``abb''、 ``abbb''、... Regexp `` T[0-9]*\.c'' 中, 使用 `` *'' 形容其前的字符集合 `` [0-9]''(一个阿拉伯数字)出现的次数 : 可为 0 次或多次. 故 Regexp `` T[0-9]*\.c''可用以表示 ``T.c''、``T0.c''、 ``T1.c''、``T2.c''、...、``T9.c''、``T00.c''、``T01.c''、``T02.c''、...、 ``T09.c''、``T10.c''、...``T99.c''、``T000.c''、... [ \<] `` \< Regexp'' 表示一个出现于"前缀"且又合于(match)该 Regexp 的字符串 (用法见下例). [ \>] ``Regexp \>'' 表示一个出现于"字末"且又合于(match)该 Regexp 的字符串. 这里所谓的``字(word)''系指被 tab、逗点、句点或空格符(space) 所分隔开的字符串. [例如 :] 资料 ``One is red, and the other is white.'' 中 字符串 ``One'', ``is'', ``red'', ``and'', ``the'', ``other'', ``is'', ``white'' 便是所谓的 "字(word)". 而该资料列中, 合于 Regexp ``[Tt]he''的字符串如下(粗体字标示) ``One is red, and the other is white.'' 合于 Regexp `` \<[Tt]he\>''却仅有(粗体字标示) ``One is red, and the other is white.'' 因同时使用`` \<''及`` \>'' 限制合于 Regexp `` [Tt]he''的字符串, 必须紧接于前缀及字尾之间; 故 ``other''中的子字符串 ``the''并不合于这个 Regular Expression. [注 :] \<, \> 这二个特殊字符, 并不是很通用. 请参考 Appendix A 中的附表. \( ... )\ 于 Regular Expression 中使用 `` \(''``{ \)}''来括住一部分的 Regular Expression; 其后可用 `` \1'''来表示第一次被`` \('' `` \)'' 括住的部份. 若 Regular Expression 中使用了数次`` \('' `` \)'' 来括住不同的部分, 则依次使用 ``\1'', `` \2'', `` \3'' ,...(最多可用到 `` \9'')来 表示之前括住的 Regular Expression. 其用法如下 : [用法一.] 例如: 欲表示像``aa'',``bb'',``cc'',...``zz'' 等字符串. 使用 Regexp `` [a-z]''则表示任一个小写的英文字母. 使用 Regexp `` [a-z][a-z]''则表示二个任意的小写英文字母. 它除表示 ``aa'',``bb'',``cc'',...``zz''等字符串外, 也可表示``ab'', ``ac'',``ad'',...等字符串(这不是题意所要求的字符串). 这时可以`` \('' `` \)'' 来括住第一个 `` [a-z]'' (Regular Expression 解译的程序, 会暂时记录实际找寻 到的英文字母). 之后, 便可以 Regexp ``\1'' 来指定适才被记 录下的英文字母即为所要找寻字符串的第二个字符. 故正确的表示法如下 : Regexp `` \([a-z]\)\1'' 例如 : 欲表示像 ``789w987'', ``abcwcba'', ``theweht'',....等具对称性 的字符串.(该字符串的特征是 ``w''之前后三个字符相互对称) 该类字符串的表示法如 下 : Regexp `` \(.\)\(.\)\(.\)w\3\2\1" Regexp中`` .''表示任意一个字符. 因字符``w''之前出现的三个字符并无 任何限制, 故可用 `` ...''表之. 但每个`` .''分别用 `` \('',`` \)'' 括住, 之后便可使用 `` \1'', `` \2'', `` \3'' 分别代表将来实际匹配到的前三个字符. 用法二. 进行字符串找寻并置换(Replace)时, 若将被置入的新字符串不是一个固定的字符串, 与被找到的原字符串有关时(见下例说明). 此时, 可先以 \( \)来括住一部分的Regular Expression; 再于将被新置入的字符串中使用`` \1'', `` \2'',... 来表示当时被找到的字符串(或其子字符串). 例 : 欲找出档案中具有 ``prog12.c'', ``prog9.c'', ``prog832.c'',... 等式样的字符串, 并将其置换成(以上列三个字符串为例) ``[ note 12]'', ``[ note 9]'', ``[ note 832]''. 在这例子中, 因事先不知道所找寻到的字符串(prog数字.c)中的 数字 为何, 故无法事先决定应换成什么新字符串. 合于本例所要找寻的字符串其 Regular Expression 为 : Regexp `` prog[0-9][0-9]*\.c'' 上式中 `` [0-9][0-9]*'' 表一位或一位以上的阿拉伯数字, 因 执行前并不知道该部分实际会匹配什么数值, 故找到的字符串将来应置换 成什么, 事前无法指定. 这情况, 也可用`` \('',`` \)'' 来括住 `` [0-9][0-9]* '', 在置换的新字符串中再以 \1 表示找寻时实际匹配到的数字. 读者可编辑一数据文件, 再以sed执行下列命令, 观察其执行结果. $sed -e 's/ prog\([0-9][0-9]*\)\.c/[ note \1]/g' 资料文件名 \{ 数字, 数字\} 一种于 Regular Expression 中形容其前的字符或字符 集合出现次数的表示法. 其型态与用法如下 : \{下限数字, 上限数字\} 例如 : Regexp "[0-9]\{2,4\}"用以表示2到4位的阿拉伯数字. { 数字} 例如 : Regexp `` ax\{99\}'' 用以表示一个 ``a'' 之后接上99个 ``x'' 所组成的字符串. \{下限数字, \} 例如 : Regexp `` ax\{2,\}'' 用以表示一个 ``a'' 之后接上2个或更多的 ``x''所组成的字符串. + 形容其前的字符或字符集合出现一次或一次以上(注三). 例如 : Regexp `` [0-9]+'' 用以表示一位或一位以上的数字. ? 形容其前的字符或字符集合可出现一次或不出现(注三). [例如 :] Regexp ``[+-]?[0-9]+'' 表示数字(一位以上)之前可出现一个正负号 或不出现正负号. [ (...)] 用以括住一群字符,且将之视成一个group(见下面说明)(注三) 例如 : Regexp `` 12+'' 表示字符串 "12","122","1222","12222",... Regexp `` (12)+'' 表示字符串 "12","1212","1212","1212".... 上式中字符串 ``12''以( )括住,整个视为一个group, 故被重复符号``+'' 所形容的是``12''而非 ``2'', 重复出现的也是 ``12''. | 表示逻辑上的 "or" (注三) 例如 : Regexp `` Oranges?|apples?|water'' 可用以表示字符串``Orange'', ``Oranges'' 或 ``apple'', ``apples'' 或 ``water'' 注三 : 上列 + , ?, (...), | 等用法, 为 Extended Regular Expression 中新增列的用法. awk 及 egrep 中所使用的 Regular Expression 即为 Extended Regular Expression. 但 vi, sed, grep,...等软件 中并无这些用法. & ``&''并非 Regular Expression 中的特殊字符. 但以 Regular Expression 进行字符串找寻置换(Replace)时, 常会用到 ``\&''. \ 在许多 Unix tool 中, 当 ``\&''出现在『将被置入的新字符串』时, 它用以表示 ``实际被找到合于所指定的 Regular Expression 的字符串'' (见下例说明) 例如 : 找出档案中所有合乎 Regexp ``a[0-9]*\.c'' 的字符串, 并在其前后加上小 括号.依题意要求, 档案中所有如 ``a12.c'', ``a932.c'', ``a45.c'' ,...等字符串都应置换为 ``(a12.c)'', ``(a932.c)'', ``(a45.c)'',.. . . 遇到这情况,可令『将被置入的新字符串』为 `` (&)'' 此时, ``&''便是用来表示实际上被找到合于 Regexp ``a[0-9]*\.c'' 的字符串. 下列是使用 UNIX 上不同的工具, 来处理本例要求的字符串置换. vi 以 vi 编辑该档案,并在 vi 命令输入模式 下输入 : s/a[0-9]*\.c/(&)/g sed 执行如下命令 ( $ 表 Shell 命令列的提示符号 ) $ sed -e 's/a[0-9]*\.c/ (&)/g' 数据文件名称 awk 执行如下命令 ( $ 表 Shell 命令列的提示符号 ) $ awk '{ gsub(/a[0-9]*\.c/, "(&)"); print }' 数据文件名称 -------------------------------------------------------------------------------- Note 2: 上列字符在 Regular Expression 中代表特殊意义, 称之为 特殊字符. 但 Unix 中不同的指令对 Regular Expression 的解释能力不尽相同, 故对特殊字符也有不同的认定. 请参考尾页附表. 使用 Regular Expression 时的注意事项 学习 Regular Expression 除了应了解其中特殊字符所代表的意义外; 在实际应用时, 也有一些应该注意的事项. 倘若忽略了这些特点, 往往会 造成字符串无法正确比对, 而导至结果错误. 本节除了介绍这些应予留心的事 项外, 也提供各软件在解读 Regular Expression, 进行字符串比对时所依据的 二项重要原则. 接受 Regular Expression 的指令或工具, 它们找寻字符串时系按照下列二原则: 由左往右进行字符串找寻. 尽可能寻找最长且合于所指定 Regular Expression 的字符串. 例如 : 应用 Regexp `` a.*b''(代表以"a"开头以"b"结尾 的任意字符串),于数据列 ``12 3ab0aab4 56'' 中找寻合于该条件 的字符串. 该资料列中合于 Regexp `` a.*b'' 的字符串有 ``ab'', ``aab'', ``ab0aab''. 但按上列二原则「由左往右找, 且尽可能寻 找最长的字符串」 实际上被找到的字符串将为 ``ab0aab''. Regular Expression 有许多不同的版本 UNIX 中不同的指令对同一个 Regular Expression 可能会有不同的解释. 原因是这些指令无法完全解释前节所述 Regular Expression 中所有的特殊字符. 这就是所谓 "Regular Expression 有许多不同的版本" 例如 : egrep 中对 Regexp `` an?'' 解释成字符串 ``a'' 或 ``an''. 但 vi 中对 Regexp `` an?'' 只解释成字符串 ``an?''. 因为 vi 中并不把 `` ?'' 当成 Regular Expression 的特殊字原解释. Appendix A 附表 中列出 UNIX 中常用的指令及它所接受的 Regular Expression 特殊字符. 勿将Shell上所使用的字符串表示法(Pattern Matching Notation) 与 Regular Expression 混淆. Regexp `` a*'' 用以表示一个完全由字符 "a" 所组成的任意长度字符串. 但在 Shell 命令列上执行 ``ls a*'', 却会列出目前工作目录下所有以 "a" 开头的档案与子目录.两者对 ``a*'' 的解释并不相同. 因为 Shell 所接受的是另一种名为 ``Pattern Matching Notation'' 的表示法, 两者并不相同请勿混淆. 在含有中文之文字文件中, 使用 Regular Expression 进行字符串找寻时, 可能会发生错误. 譬如 : 找寻左大括号"{", 结果中文的"程"也被找出. 这并非 Regular Expression 出了错误. 因每个中文字都是由 2 个 bytes 组成, 而中文``程''字的后一个 byte 恰 被解释成``{''.所以除非所使用的指令有自动避开中文字的功能, 否则中文字的后一个 byte 被误判的机率并不低. 故读者在含有中文文字的档案中, 进行字符串找寻并置换时, 最好是逐次确认后再行置换. 并非所有软件都接受 Regular Expression(有解读 Regular Expression 的能力). 一般而言,就算某软件(工具)可接受 Regular Expression , 它也并非把所有的字 串或参数当成 Regular Expression 解释. 读者使用 Regular Expression 时, 应先确定该软件会把该些字符串当成 Regular Expression 解释(可翻查其 manual page), 如此才可获得正确的结果. 范 例 本节列出数个 Regular Expression 的应用简例, 供读者参考. 由这些范例中, 读者可一窥实际应用时, 如何藉由 Regular Expression 来表达字符串, 来完成 某些目的. 至于各指令像 vi, sed, awk, ...中之语法说明已非本文所能涵盖, 读者请自行参考相关书籍. a. 将档案中所有字符串 ``Regular Expression'' 或 ``Regular expression'' 换成 ``Regexp''. 以 vi 编辑该档案, 并在 vi 命令输入模式下执行 : :1,$ s/ Regular [Ee]xpression/Regexp/g b. 将档案中所有具 ``ddd-dddd'' 特征的字符串(d表阿拉伯数字)之前插入字符串 ``Tel :''. 以 vi 编辑该档案, 并在, vi 命令输入模式下执行 : :1,$ s/[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]/Tel:&/g 说明 : `` &'' 代表执行时实际合于该 Regular Expression 的字符串. c. 将档案中所有俱有 `` program数字.c'' 特征的字符串换成 ``test数字.f''. 解法 : 以vi编辑该档案, 并在vi命令输入mode下执行 : :1,$ s/ program\([0-9][0-9]**\)\.c/test\1.f/g 说明 : Regexp `` [0-9][0-9]*'' 表示一位或一位以上的阿拉伯数字. `` \1'' 被找到的字符串中的数值部分. (被\(...\)括住的部分). d. 将档案中第5-13行, 整个区域往右移5格(空格符). 解法 : 以vi编辑该档案, 并在vi命令输入mode下执行 :5,13 s/ .*/ &/ 说明 : Regexp `` .*" 用以 match 整个数据列(之后以&表之). 并用 `` &''(5个空白及原先之资料列)取代该列资料. e. 将上例档案中的数据列(5-13行), 往左移回3格. 解法 : 以vi编辑该档案, 并在vi命令输入mode下执行 :5,13 s/ \^ /// 说明 : 将行首的三个空格符换成空字符串. f. 试从一个档案的全名中分离出其路径及文件名. 解法 : 编辑如下的script并取名为 ``sepname'' awk ' BEGIN { match( ARGV[1], /.*\//) print "path=", substr(ARGV[1], 1 ,RLENGTH-1) print "name=", name = substr(ARGV[1], RLENGTH+1 ) } ' $1 } 执行 $ sepname /usr/local/bin/xdvi 结果印出 path= /usr/local/bin name= xdvi g. 将档案中以``From''或``from''为行首的数据打印出 执行 $ awk '/^[Ff]rom/ ' 数据文件文件名 h. 去除挡案中空白行 执行 $ sed -e "/ ^$/d" 后 语 虽然 Regular Expression 仅是一种字符串的表示方式, 但从上列的范例 中不难窥出, 配合接受 Regular Expression 的指令或工具, 其应用面 将远超出找寻字符串及置换字符串. 使用 Regular Expression 不仅扩大了 字符串的表达能力, 让使用者很容易进行字符串判断; 使数据处理的过程便 为更为迅速便利. Appendix : Test using Regular Expression in various environments HP-UX 下表列出测试 HP-UX Release 9.0 中常见的工具对 Regular Expression 中各种特殊字符的接受能力. ex vi sed awk grep egrep 说明 . * * * * * * * * * * * * * ^ * * * * * * $ * * * * * * \ * * * * * * [ ] * * * * * * \( \)与\1...\9 合用(一) * * 把\1...\9用于 Regular Expression 中 \( \)与\1...\9 合用(二) * * * - - 把\1...\9用于欲置换的新字符串中 {重复次数} * * {下限,上限} * * {下限, } * * \< \> * * + * * ? * * | * * ( ) * * \ * * * * - - * 表示该指令有解释这种特殊字符的能力. - 表示未测试该项功能. Sun Solaris 2.X 下表列出测试 Sun Solaris 2.x 中常见的工具对 Regular Expression 中各种特殊字符的接受能力 ex vi sed awk grep egrep 说明 . * * * * * * * * * * * * * ^ * * * * * * $ * * * * * * \ * * * * * * [ ] * * * * * * \( \)与\1...\9 合用(一) * * * * 把\1...\9用于 Regular Expression 中 \( \)与\1...\9 合用(二) * * * - - 把\1...\9用于欲置换的新字符串中 {重复次数} * * * * {下限,上限} * * * * {下限, } * * * * \< \> * * * * + * * ? * * | * * ( ) * * \ * * * * - - * 表示该指令有解释这种特殊字符的能力. - 表示未测试该项功能. AIX 3.2.5 下表列出测试 AIX 3.2.5 中常见的工具对 Regular Expression 中各种特殊字符的接受能力. ex vi sed awk grep egrep 说明 . * * * * * * * * * * * * * ^ * * * * * * $ * * * * * * \ * * * * * * [ ] * * * * * * \( \)与\1...\9 合用(一) * * 把\1...\9用于 Regular Expression 中 \( \)与\1...\9 合用(二) * * * - - 把\1...\9用于欲置换的新字符串中 {重复次数} * * {下限,上限} * * {下限, } * * \< \> * * + * * ? * * | * * ( ) * * \ * * * * - - * 表示该指令有解释这种特殊字符的能力. - 表示未测试该项功能. GNU Tools 下表列出测试 GNU 所提供的工具对 Regular Expression 中各种特殊字符的接受能力. sed awk grep -G egrep -E emacs 说明 . * * * * * * * * * * * ^ * * * * * $ * * * * * \ * * * * * [ ] * * * * * \( \)与\1...\9 合用(一) * * 把\1...\9用于 Regular Expression 中 \( \)与\1...\9 合用(二) * - - * 把\1...\9用于欲置换的新字符串中 {重复次数} * * {下限,上限} * * {下限, } * * \< \> * * * * + * * * ? * * * | * * ( ) * * \ * * - - * 表示该指令有解释这种特殊字符的能力. - 表示未测试该项功能.
各种工具之正则表达式语法比较
在各种常用的工具中,
正则表达式如此的相似却又不同。
下表列出了一些常用的正则表达式,以及其不同之处。
项目总多,遗漏必有不少,请各位看官不吝指出。
以perl的正则为基准,不同的用法以粉红色标出。
grep 2.5.1
egrep 2.5.1
sed 3.02 sed 4.07
awk 3.1.1
perl 5.8.0
vim 6.1
JavaScript ??
转义
\
\
\
\
\
\
\
行头
^
^
^
^
^
^
^
行尾
$
$
$
$
$
$
$
n个 {n} {m,n} {m,} {,n}
\{n\}
{n}
\{n\}
{n}或\{n\} 仅定义 --posix 或 --re-interval有效(要表达}和{,得用\\{和\\} 没有定义--posix或--re-interval时,不能用{n}的语法, \}\{和}{同义
{n}
\{n\}
{n}
{0,}
*
*
*
*或\*, (要表达*,得用\\*)
*
*
*
{1,}
\+
+
\+
+或\+, (要表达+, 得用\\+)
+
\+
+
{0,1}
\?
?
\?
?或\?, (要表达?, 得用\\?)
?
\?
?
任意字符
.
.
.
. 含\n.
. /s修饰后则含\n
. 除\n
. 除\n
(pat) 匹配并获结果
\(pat\)
(pat)
\(pat\)
(pat)或\(pat\) (要表达括号,用\\( \\) )
(pat)
\(pat\)
(pat)
(?:pat) 匹配但不获结果
不支持
不支持
不支持
不支持
(?:pat)
不支持
(?:pat)
(?=pat) 等于预查
不支持
不支持
不支持
不支持
(?=pat)
不支持
(?=pat)
(?!pat) 不等预查
不支持
不支持
不支持
不支持
(?!pat)
不支持
(?!pat)
| 或
\|
|
\|
|或\| (要表达|,得用\\|)
|
\|
|
其中任意字符
[xyz]
[xyz]
[xyz]
[xyz]
[xyz]
[xyz]
[xyz]
[.ch.] [=ch=]
不支持
不支持
[.ch.]
不支持
不支持
不支持
不支持
单词边界 \b
\b
\b
\b
不支持
\b
不支持
\b
非单词边界 \B
\B
\B
\B
不支持
\B
不支持
\B
单词左右边界 <>
\< \>
\< \>
\< \>
不支持 (><和\>\<和\\>\\<同义
不支持(><和\>\<同义
\< \>
不支持(><和\>\<同义
控制字符 /cx
不支持
不支持
\cx
不支持
\cx
不支持
\cx
数字\d
不支持
不支持
不支持
不支持
\d
\d
\d
非数字\D
不支持
不支持
不支持
不支持
\D
\D
\D
换页 \f
不支持
不支持
高版本支持
\f
\f
另义 \f表示文件名字符
\f
换行 \n
不支持
不支持
不支持
\n
\n
\n
\n
回车 \r
不支持
不支持
\r
\r
\r
\r
\r
空白 \s
不支持
不支持
不支持
不支持
\s
\s
\s
非空白 \S
不支持
不支持
不支持
不支持
\S
\S
\S
制表符 \t
不支持
不支持
高版本支持
\t
\t
\t
\t
垂直制表符 \v
不支持
不支持
高版本支持
\v
\v
另义 \v表示very magic
\v
单词字符 \w [A-Za-z0-9_]
\w
\w
\w
不支持
\w
\w
\w
非单词字符 \W [^A-Za-z0-9]
\W
\W
\W
不支持
\W
\W
\W
\xn 16进制
不支持
不支持
高版本支持
\xn
\xn
另义 \x表示[0-9A-Za-z]
\xn
\n 八进制
不支持
不支持
不支持
\n
\n
不支持
\n
\n 后向引用
\n
\n
\n
\n 仅取结果可用
\n
\n 仅取结果可用
\n
[:alnum:] 字母和数字
[:alnum:]
[:alnum:]
[:alnum:]
[:alnum:]
[:alnum:]
[:alnum:]
不支持
[:alpha:] 字母
[:alpha:]
[:alpha:]
[:alpha:]
[:alpha:]
[:alpha:]
[:alpha:]
不支持
[:cntrl:] 控制字符
[:cntrl:]
[:cntrl:]
[:cntrl:]
[:cntrl:]
[:cntrl:]
[:cntrl:]
不支持
[:digit:] 数字
[:digit:]
[:digit:]
[:digit:]
[:digit:]
[:digit:]
[:digit:]
不支持
[:graph:] 可打印字符(不含空格)
[:graph:]
[:graph:]
[:graph:]
[:graph:]
[:graph:]
[:graph:]
不支持
[:lower:] 小写
[:lower:]
[:lower:]
[:lower:]
[:lower:]
[:lower:]
[:lower:]
不支持
[:print:] 可打印字符(含空格)
[:print:]
[:print:]
[:print:]
[:print:]
[:print:]
[:print:]
不支持
[:punct:] 标点
[:punct:]
[:punct:]
[:punct:]
[:punct:]
[:punct:]
[:punct:]
不支持
[:space:] 空格
[:space:]
[:space:]
[:space:]
[:space:]
[:space:]
[:space:]
不支持
[:upper:] 大写字母
[:upper:]
[:upper:]
[:upper:]
[:upper:]
[:upper:]
[:upper:]
不支持
[:xdigit:] 16进制数字
[:xdigit:]
[:xdigit:]
[:xdigit:]
[:xdigit:]
[:xdigit:]
[:xdigit:]
不支持
[:return:]
不支持
不支持
不支持
不支持
不支持
[:return:]
不支持
[:tab:]
不支持
不支持
不支持
不支持
不支持
[:tab:]
不支持
[:escape:]
不支持
不支持
不支持
不支持
不支持
[:escape:]
不支持
[:backspace:]
不支持
不支持
不支持
不支持
不支持
[:backspace:]
不支持
转自 :
(2011-11-13 13:02)
零宽断言的意思是(匹配宽度为零,满足一定的条件/断言) 我也不知道这个词语是那个王八蛋发明的,简直是太拗口了。
零
宽断言用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像 \b ^ $ \< \>
这样的锚定作用,用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言。 断言用来声明一个应该为真的事实。正则表达式中
只有当断言为真时才会继续进行匹配。
其中零宽断言又分四种:
1)
先行断言 也叫零宽度正预测先行断言(?=exp) -- 表示匹配表达式前面的位置
例如 [a-z]*(?=ing) 可以匹配 cooking 和 singing 中的 cook 与 sing 。
注意:先行断言的执行步骤是这样的先从要匹配的字符串中的最右端找到第一个 ing (也就是先行断言中的表达式)然后 再匹配其前面的表达式,若无法匹配则继续查找第二个 ing 再匹配第二个 ing 前面的字符串,若能匹配则匹配,符合正则的贪婪性。
例如: .*(?=ing) 可以匹配 "cooking singing" 中的 "cooking sing" 而不是 cook
2)
后发断言 也叫零宽度正回顾后发断言(?<=exp) -- 表示匹配表达式后面的位置
例如(?<=abc).* 可以匹配 abcdefg 中的 defg
注意:后发断言跟先行断言恰恰相反 它的执行步骤是这样的:先从要匹配的字符串中的最左端找到第一个abc(也就是先行断言中的表达式)然后 再匹配其后面的表达式,若无法匹配则继续查找第二个 abc 再匹配第二个 abc 后面的字符串,若能匹配则匹配。
例如(?<=abc).* 可以匹配 abcdefgabc 中的 defgabc 而不是 abcdefg
3)
负向零宽断言
负
向零宽断言 (?!exp) 也是匹配一个零宽度的位置,不过这个位置的“断言”取表达式的反值,例如 (?!exp) 表示 "exp"
前面的位置,如果 "exp" 不成立 ,匹配这个位置;如果 "exp"
成立,则不匹配。同样,负向零宽断言也有“先行”和“后发”两种,负向零宽后发断言为 (?
负向零宽后发断言(?
负向零宽先行断言 (?!exp)
负向零宽断言要注意的跟正向的一样。
常用分组语法 分类 代码/语法 说明 捕获 (exp) 匹配exp,并捕获文本到自动命名的组里 (?exp) 匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp) (?:exp) 匹配exp,不捕获匹配的文本,也不给此分组分配组号 零宽断言 (?=exp) 匹配exp前面的位置 (?<=exp) 匹配exp后面的位置 (?!exp) 匹配后面跟的不是exp的位置 (? 匹配前面不是exp的位置 注释 (?#comment) 这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读
例子:
cat file
aaa bbb CD="123" fd
要取出CD后面的值:
grep -oP '(?<=CD=")\d+' file [解析]
以 CD=" 为后发断言,匹配它后面的多个数字。
cat file
Rx Optical Power: -5.01dBm, Tx Optical Power: -2.41dBm
要取出那几个分贝的值:
grep - oP '( ? < = : ) . * ? ( ? = d) ' file