正则表达式(Regular Expression)
正则表达式,又称正规表示式、正规表示法、正规表达式、规则表达式、常规表示法(英语:Regular Expression,在代码中常简写为regex、regexp或RE)。
正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本。
元字符
字符 | 描述 | 例子 |
---|---|---|
\ | 将下一个字符标记为一个特殊字符、或一个原义字符、或一个向后引用、或一个八进制转义符。 | 例如:“@H_502_32@n”匹配字符“@H_502_32@n”。“@H_502_32@\n”匹配一个换行符。序列“@H_502_32@\\”匹配“@H_502_32@\”而“@H_502_32@\(”则匹配“@H_502_32@(”。 |
. | 匹配除“@H_502_32@\n”之外的任何单个字符。要匹配包括“@H_502_32@\n”在内的任何字符,请使用像“@H_502_32@(.|\n)”的模式。 | 例如:@H_502_32@a.c 匹配abc,而@H_502_32@[.|\n]* 则匹配任意字符 |
x|y | 匹配x或y。常在括号中使用。 | 例如:“@H_502_32@z|food”能匹配“@H_502_32@z”或“@H_502_32@food”。“@H_502_32@(z|f)ood”则匹配“@H_502_32@zood”或“@H_502_32@food”。 |
[xyz] | 字符集合(character class)。匹配所包含的任意一个字符。特殊字符仅有反斜线\保持特殊含义,用于转义字符。其它特殊字符如星号、加号、各种括号等均作为普通字符。脱字符^如果出现在首位则表示负值字符集合;如果出现在字符串中间就仅作为普通字符。连字符 - 如果出现在字符串中间表示字符范围描述;如果如果出现在首位则仅作为普通字符。 | 例如:“@H_502_32@[abc]”可以匹配“@H_502_32@plain”中的“@H_502_32@a”。 |
[^xyz] | 排除型(negate)字符集合。匹配未列出的任意字符。 | 例如:“@H_502_32@[^abc]”可以匹配“@H_502_32@plain”中的“@H_502_32@p”“@H_502_32@l”“@H_502_32@i”“@H_502_32@n”。 |
[a-z] | 字符范围。匹配指定范围内的任意字符。 | 例如:“@H_502_32@[a-z]”可以匹配“@H_502_32@a”到“@H_502_32@z”范围内的任意小写字母字符。 |
[^a-z] | 排除型的字符范围。匹配任何不在指定范围内的任意字符。 | 例如:“@H_502_32@[^a-z]”可以匹配任何不在“@H_502_32@a”到“@H_502_32@z”范围内的任意字符。 |
\cx | 匹配由x指明的控制字符。 x的值必须为A-Z或a-z之一。否则,将c视为一个原义的“@H_502_32@c”字符。 |
例如:\cM匹配一个Control-M或回车符。 |
\xn | 匹配n,其中n为十六进制转义值。十六进制转义值必须为确定的两个数字长。正则表达式中可以使用ASCII编码。. | 例如:“@H_502_32@\x41”匹配“@H_502_32@A”。“@H_502_32@\x041”则等价于“@H_502_32@\x04&1”。 |
\num | 向后引用(back-reference)一个子字符串(substring),该子字符串与正则表达式的第num个用括号围起来的子表达式(subexpression)匹配。其中num是从1开始的正整数,其上限可能是99。 详见 分组与后向引用 | 例如:“@H_502_32@(.)\1”匹配两个连续的相同字符。 |
\n | 标识一个八进制转义值或一个向后引用。如果\n之前至少n个获取的子表达式,则n为向后引用。否则,如果n为八进制数字(0-7),则n为一个八进制转义值。 | |
\nm | 标识一个八进制转义值或一个向后引用。如果\nm之前至少有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匹配版权符号(©)。 |
量词(用在字符或()之后)
元字符 | 描述 | 例子 |
---|---|---|
* | 量词,匹配前面的子表达式零次或多次。 | 例如:zo*能匹配“@H_502_32@z”、“@H_502_32@zo”以及“@H_502_32@zoo”。*等价于{0,}。 |
+ | 量词,匹配前面的子表达式一次或多次。 | 例如:“@H_502_32@zo+”能匹配“@H_502_32@zo”以及“@H_502_32@zoo”,但不能匹配“@H_502_32@z”。+等价于{1,}。 |
? | 量词,匹配前面的子表达式零次或一次。 | 例如:“@H_502_32@do(es)?”可以匹配“@H_502_32@do”或“@H_502_32@does”中的“@H_502_32@do”。?等价于{0,1}。 |
{n} | 量词,n是一个非负整数。匹配确定的n次。 | 例如:“@H_502_32@o{2}”不能匹配“@H_502_32@Bob”中的“@H_502_32@o”,但是能匹配“@H_502_32@food”中的两个o。 |
{n,} | n是一个非负整数。至少匹配n次。可看做是{n,m}中m默认为无限。 | 例如:“@H_502_32@o{2,}”不能匹配“@H_502_32@Bob”中的“@H_502_32@o”,但能匹配“@H_502_32@foooood”中的所有o。“@H_502_32@o{1,}”等价于“@H_502_32@o+”。“@H_502_32@o{0,}”则等价于“@H_502_32@o*”。 |
{n,m} | m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。 | 例如:“@H_502_32@o{1,3}”将匹配“@H_502_32@fooooood”中的前三个o。“@H_502_32@o{0,1}”等价于“@H_502_32@o?”。请注意在逗号和两个数之间不能有空格。 |
? | 当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。如:*?、+?、??、{n,m}?、{n,}? | 例如:对于字符串“@H_502_32@oooo”,“@H_502_32@o+?”将匹配单个“@H_502_32@o”,而“@H_502_32@o+”将匹配所有“@H_502_32@o”。 |
边界匹配
元字符 | 描述 | 例子 |
---|---|---|
^不位于[]内 | 匹配输入字符串的开始位置。如果设置了RegExp对象的Multiline属性,^也匹配“@H_502_32@\n”或“@H_502_32@\r”之后的位置。 | 例如:^\d{3} 与搜索字符串开始处的 3 个数字匹配。 |
$ | 匹配输入字符串的结束位置。如果设置了RegExp对象的Multiline属性,$也匹配“@H_502_32@\n”或“@H_502_32@\r”之前的位置。 | 例如:\d{3}$ 与搜索字符串结尾处的 3 个数字匹配。 |
\b | 匹配一个单词开头与结尾也即边界,也就是指单词和空格间的位置。相当于@H_502_32@(? | 例如:“@H_502_32@er\b”可以匹配“@H_502_32@never”中的“@H_502_32@er”,但不能匹配“@H_502_32@verb”中的“@H_502_32@er”。 |
\B | 匹配非单词边界。 | 例如:“@H_502_32@er\B”能匹配“@H_502_32@verb”中的“@H_502_32@er”,但不能匹配“@H_502_32@never”中的“@H_502_32@er”。 |
\A | 匹配字符串的开头,但不匹配内部行的开头。 | 例如:“@H_502_32@\Aabc”能匹配“@H_502_32@abcdef”中的“@H_502_32@abc”,但不能匹配“@H_502_32@aabcd”中的“@H_502_32@abc”。 |
\z | 匹配字符串的结尾,但不匹配内部行的结尾。 | 例如:“@H_502_32@def\z”能匹配“@H_502_32@abcdef”中的“@H_502_32@def”,但不能匹配“@H_502_32@defdefabc”中的“@H_502_32@def”。 |
分组语法
元字符 | 描述 | 例子 |
---|---|---|
(pattern) | 匹配pattern,并捕获文本到自动命名的组里。该子字符串用于向后引用。所获取的匹配可以从产生的Matches集合得到,在VBScript中使用SubMatches集合,在JScript中则使用$0…$9属性。要匹配圆括号字符,请使用“@H_502_32@\(”或“@H_502_32@\)”。详细见后面分组与后向引用。 | 例如:\b(\w+)\b\s+\1\b可以用来匹配重复的单词,像go go,或者kitty kitty。\1则代表了前面()捕捉到的字符串 |
(?:pattern) | 匹配pattern,但不捕获匹配的文本,也不给此分组分配组号。也就是说这是一个非获取匹配,不存储匹配的子字符串用于向后引用。因为我们经常会使用到()小括号,使用此会节约资源。这在使用或字符“@H_502_32@(|)”来组合一个模式的各个部分是很有用。 | 例如:“@H_502_32@industr(?:y|ies)”就是一个比“@H_502_32@industry|industries”更简略的表达式。 |
(?=pattern) | 正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。 | 例如:“@H_502_32@Windows(?=95|98|NT|2000)”能匹配“@H_502_32@Windows2000”中的“@H_502_32@Windows”,但不能匹配“@H_502_32@Windows3.1”中的“@H_502_32@Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 |
(?!pattern) | 正向否定预查,在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。 | 例如:“@H_502_32@Windows(?!95|98|NT|2000)”能匹配“@H_502_32@Windows3.1”中的“@H_502_32@Windows”,但不能匹配“@H_502_32@Windows2000”中的“@H_502_32@Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始 |
(?<=pattern) | 反向肯定预查,与正向肯定预查类似,只是方向相反。 | 例如:“@H_502_32@Windows(?!95|98|NT|2000)”能匹配“@H_502_32@Windows3.1”中的“@H_502_32@Windows”,但不能匹配“@H_502_32@Windows2000”中的“@H_502_32@Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始 |
(?<!pattern) | 反向否定预查,与正向否定预查类似,只是方向相反。 | 例如: “@H_502_32@(?<!95|98|NT|2000)Windows”能匹配“@H_502_32@3.1Windows”中的“@H_502_32@Windows”,但不能匹配“@H_502_32@2000Windows”中的“@H_502_32@Windows”。 |
预定义字符集(可以写在字符集[...]中)
元字符 | 描述 | 等价于 |
---|---|---|
\d | 匹配一个数字字符。 | 等价于[0-9]。 |
\D | 匹配一个非数字字符。 | 等价于[^0-9]。 |
\w | 理论上匹配包括下划线的任何单词字符。 实际上:在支持ASCII码的语言中,如JavaScript,“\w”等价于“@H_502_32@[A-Za-z0-9_]”; 在支持Unicode的语言中,如.NET,默认情况下,“\w”除可以匹配@H_502_32@[a-zA-Z0-9_]外,还可以匹配一些Unicode字符集,如汉字,全角数字等等。 几乎所有常见的语言都遵循这样一个规律,只有Java是个例外。 |
等价于“@H_502_32@[A-Za-z0-9_]”。 |
\W | 匹配任何非单词字符。类似上面 | 等价于“@H_502_32@[^A-Za-z0-9_]”。 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等。 | 等价于[ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符。 | 等价于[^ \f\n\r\t\v]。 |
不可打印字符
元字符 | 匹配 | 等价于 |
---|---|---|
\f | 匹配一个换页符。 | 等价于\x0c和\cL。 |
\n | 匹配一个换行符。 | 等价于\x0a和\cJ。 |
\r | 匹配一个回车符。 | 等价于\x0d和\cM。 |
\t | 匹配一个制表符。 | 等价于\x09和\cI。 |
\v | 匹配一个垂直制表符。 | 等价于\x0b和\cK。 |
优先级
优先权 | 符号 |
---|---|
最高 | \ |
高 | ( )、(?: )、(?= )、[ ] |
中 | *、+、?、{n}、{n,}、{m,n} |
低 | ^、$、中介字符 |
最低 | l |
注释
括号的另一种用途是通过语法(?#comment)来包含注释。
例如:2[0-4]\d(?#200-249)|250-5|[01]?\d\d?(?#0-199)。
其他
分组与后向引用
使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。
默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。
后向引用用于重复搜索前面某个分组匹配的文本。例如,\1代表分组1匹配的文本。(不同语言可能表达不大一样)
- 分组0对应整个正则表达式
- 实际上组号分配过程是要从左向右扫描两遍的:第一遍只给未命名组分配,第二遍只给命名组分配--因此所有命名组的组号都大于未命名的组号
例如:
@H_502_32@\b(\w+)\b\s+\1\b可以用来匹配重复的单词,像go go,或者kitty kitty。这个表达式首先是一个单词,也就是单词开始处和结束处之间的多于一个的字母或数字@H_502_32@(\b(\w+)\b),这个单词会被捕获到编号为1的分组中,然后是1个或几个空白符@H_502_32@(\s+),最后是分组1中捕获的内容(也就是前面匹配的那个单词)@H_502_32@(\1)。
也可以自己指定子表达式的组名。要指定一个子表达式的组名,请使用这样的语法:@H_502_32@(?<Word>\w+)(或者把尖括号换成'也行:@H_502_32@(?'Word'\w+)),这样就把\w+的组名指定为Word了。要反向引用这个分组捕获的内容,你可以使用@H_502_32@\k<Word>,所以上一个例子也可以写成这样:@H_502_32@\b(?<Word>\w+)\b\s+\k<Word>\b。
Note:不同语言也许语法上会有些许出入。
@H_502_32@\w的范围
在支持ASCII码的语言中,如JavaScript,“@H_502_32@\w”等价于@H_502_32@[a-zA-Z0-9_];
在支持Unicode的语言中,如.NET,默认情况下,“@H_502_32@\w”除可以匹配@H_502_32@[a-zA-Z0-9_]外,还可以匹配一些Unicode字符集,如汉字,全角数字等等。
几乎所有常见的语言都遵循这样一个规律,只有Java是个例外。在Java中,“@H_502_32@\w”的表现是比较奇怪的,Java是支持Unicode的,但Java的正则中的“@H_502_32@\w”却是等价于@H_502_32@[a-zA-Z0-9_]的。
先来看一下“@H_502_32@\w”在几种语言中匹配的例子
Javascript:
<script language="javascript"> var str = "abc_123中文_d3=efg汉字%"; var reg = /\w+/g; var arr = str.match(reg); if(arr != null) { for(var i=0;i<arr.length;i++) { document.write(arr[i] + "<br />"); } } </script> /*-------- JavaScript中输出-------- abc_123 _d3 Efg */
C#:
string test = "abc_123中文_d3=efg汉字%"; MatchCollection mc = Regex.Matches(test,@"\w+"); foreach (Match m in mc) { richTextBox2.Text += m.Value + "\n"; } /*-------- C#中输出-------- abc_123中文_d3 efg汉字 */
Java:
String test = "abc_123中文_d3=efg汉字%"; String reg = "\\w+"; Matcher m = Pattern.compile(reg).matcher(test); while(m.find()) { System.out.println(m.group()); } /*-------- Java中输出-------- abc_123 _d3 Efg */
可以看到,“\w”在Java中的输出和JavaScript中是一样的,都是只支持ASCII字符。
@H_502_32@
\b的范围
见语言中“@H_502_32@\w”的范围确定了,那么是不是可以认为“@H_502_32@\b”的匹配范围与“@H_502_32@\w”也是一致的呢?再看下下面的例子:
源字符串:@H_502_32@abc_123中文_d3=汉字efg
正则表达式:@H_502_32@.\b.
JavaScript:
<script language="javascript"> var str = "abc_123中文_d3=efg汉字%"; var reg = /.\b./g; var arr = str.match(reg); if(arr != null) { for(var i=0;i<arr.length;i++) { document.write(arr[i] + "<br />"); } } </script> /*-------- JavaScript中输出-------- 3中 文_ 3= g汉 */
C#:
string test = "abc_123中文_d3=efg汉字%"; MatchCollection mc = Regex.Matches(test,@".\b."); foreach (Match m in mc) { richTextBox2.Text += m.Value + "\n"; } /*-------- C#中输出-------- 3= 字% */
Java:
String test = "abc_123中文_d3=efg汉字%"; String reg = ".\\b."; Matcher m = Pattern.compile(reg).matcher(test); while(m.find()) { System.out.println(m.group()); } /*-------- Java中输出-------- 3= 字% */
可以看到,Java的输出和.NET是一致的,“@H_502_32@\b”在Java中是支持Unicode的。
Note:“@H_502_32@\b”用在正则中,通常情况下都是表示单词边界的,只有在字符组中,它表示的是退格键。
如:即@H_502_32@[a-z\b]此处的“@H_502_32@\b”表示的是退格键,而不是单词边界。
所以总的来说,Java中的“@H_502_32@\w”是很奇怪的,而“@H_502_32@\b”是与其它语言表现一致的,在使用时需要注意。
转载请注明来自: blog.csdn.net/epluguo
附:
在线正则表达式验证器:
https://www.debuggex.com
https://mengzhuo.org/regex/
参考:
http://en.wikipedia.org/wiki/Regularexpression#citenote-PerlBestPractices-33
http://www.greenend.org.uk/rjk/tech/regexp.html
http://zh.wikipedia.org/wiki/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F
http://msdn.microsoft.com/zh-cn/library/ae5bf541(v=vs.100).aspx
http://deerchao.net/tutorials/regex/regex.htm
http://www.cnblogs.com/huxi/archive/2010/07/04/1771073.html