正则表达式是由普通字符和以及特殊字符(称为“元字符”)组成的文字模式。模式描述在搜索文本时要匹配的一个或多个字符串。
普通字符
普通字符包括没有显式指定为元字符的所有可打印和不可打印字符。这包括所有大写和小写字母、所有数字、所有标点符号和一些其它符号。
非打印字符
字符 | 描述 |
\cx | 匹配由x指明的控制字符。例如,\cM匹配一个Control-M或回车符。x必须是A-Z或a-z之一。否则将c视为一个原义的‘c’字符。 |
\f | 匹配一个换页符。等价于\x0c和\cL。 |
\n | 匹配一个换行符。等价于\x0a和\cJ。 |
\r | 匹配一个回车符。等价于\x0d和\cM。 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[\f\n\r\t\v]。注意Unicode正则表达式会匹配全角空格符。 |
\S | 匹配任何空白字符。等价于[^ \f\n\r\t\v]。 |
\t | 匹配一个制表符。等价于\x09和\cl。 |
\v | 匹配一个垂直制表符。等价于\x0b和\cK。 |
特殊字符(元字符)
特别字符 | 描述 |
$ | 匹配输入字符串的结尾位置。如果设置了RegExp对象的Multiline属性,则$也匹配'\n'或'r'。 |
() | 标记一个表达式的开始和结束位置。子表达式可以获取供以后使用。 |
* | 匹配前面的子表达式零次或者多次。 |
+ | 匹配前面的子表达式零次或者一次。 |
. | 匹配除换行符\n之外的任何单字符。 |
[ | 标记一个中括号表达式的开始。 |
? | 匹配前面的子表达式一次或者零次,或者指明一个非贪婪限定符。 |
\ | 将下一个字符标记为或特殊字符、或原义字符或向后引用、或八进制转义符。 |
^ | 匹配输入字符串的开始位置,除非在方括号表达式中使用,当该符号在方括号表达式中使用时,表示不接受改方括号表达式中的字符集合。 |
{ | 标记限定符表达式的开始。 |
| | 指明两项之间的一个选择。 |
限定符
限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。有*或+或?或{n}或{n,}或{n,m}共6种。
字符 | 描述 |
* | 匹配前面的子表达式0次或多次。等价于{0,} |
+ | 匹配前面的子表达式1次或多次。等价于{1,} |
? | 匹配前面的子表达式0次或1次。等价于{0,1} |
{n} | n是一个非负整数。匹配确定的n次。 |
{n,} | n是一个非负整数。至少匹配n次。 |
{n,m} | m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。请注意在逗号和两个数之间不能有空格。 |
*和+限定符都是贪婪的,因为它们会尽可能多的匹配文字,只有在它们后面加上一个?就可以实现非贪婪或者最小匹配。
定位符
定位符用来描述字符串或者单词的边界。
字符 | 描述 |
^ | 匹配输入字符串开始的位置。如果设置了RegExp对象的Multiline属性,^还会与\n或\r之后的位置匹配。 |
$ | 匹配输入字符串结尾的位置。如果设置了RegExp对象的Multiline属性。$还会与\n或\r之前的位置匹配。 |
\b | 匹配一个单词边界,即字与空格间的位置。 |
\B | 非单词边界匹配。 |
选择
用圆括号将所有选项括起来,相邻的选项之间用|分隔。但用圆括号会有一个副作用,使相关的匹配会被缓存,此时可用?:,放在第一个选项前来消除这种副作用。
?:是非捕获元之一,还有两个非捕获元是?=和?!,这两个还有跟多的含义,前者为正向预查,在任何开始匹配圆括号内的正则表达式模式的位置来匹配搜索字符串,后者为负向预查,在任何开始不匹配该正则表达式模式的位置来匹配搜索字符串。
元字符总结
字符 | 描述 |
\ | 将下一个字符标记为一个特殊字符、或一个原义字符、或一个后向引用、或一个八进制转义符。例如,'n'匹配字符“n”。'\n'匹配一个换行符。序列'\\'匹配'\',而‘\(’匹配“(”。 |
^ | 匹配输入字符串的开始位置。如果设置了多行属性,^也匹配'\n'或'\r'之后的位置。 |
$ | 匹配输入字符串的结束位置。如果设置了多行属性,$也匹配'\n'或'r'之后的位置。 |
* | 匹配前面的子表达式零次或者多次。等价{0,} |
+ | 匹配前面的子表达式一次或者多次。等价于{1,} |
? | 匹配前面的子表达式一次或者0次。等价于{0,1} |
{n} | n是一个非负整数。匹配确定的n次。 |
{n,} | n是一个非负整数。至少匹配n次。 |
{n,m} | n,m都是非负整数,其中n<=m。最少匹配n次,最多匹配m次。 |
? | 当该字符紧跟在任何一个其它限制符(*, +, ?, {n}, {n,}, {n, m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。比如,对于字符串,“oooo”,'o+?'将匹配单个‘o’,而‘o+’将匹配所有的'o'。 |
. | 匹配除换行符之外的任何单个字符。要匹配包括'\n'在内的任何字符,请使用“(.|\n)”模式。 |
(pattern) | 匹配pattern并获取这一匹配。所获取的匹配可以从产生的Matches集合中得到,在VBscript中使用SubMatches集合,在Jscript中则使用$0...$9属性。 |
(?:pattern) | 匹配pattern但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。 |
(?=pattern) | 正向肯定预查(look ahead positive assert),在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,“Windows(?=95|98|NT|2000)”能匹配“Windows2000”中的Windows,但是不能匹配“Windows3.1”中的“Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 |
(?!pattern) | 正向否定预查(negative assert),在任何不匹配pattern的字符串开始出匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,“Windows(?=95|98|NT|2000)”能匹配“Windows3.1”中的“Windows”,但不能匹配“Windows2000”中的“Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 |
(?<=pattern) | 反向(look behind)肯定预查,与正向肯定预查类似,只是方向相反。例如,“(?<=95|98|NT|2000)Windows”能匹配“2000Windows”中的"Windows",但是不能匹配"3.1Windows"中的“Windows”。 |
(?<!pattern) | 反向否定预查,与正向否定预查类似,只是方向相反。例如,“?<!95|98|NT2000”能匹配“3.1Windows”中的“Windows”但不能撇配“2000Windows”中的Windows |
x|y | 匹配x或y。例如‘z|food’能匹配“z”或者“food”。'(z|f)ood'则匹配“zood”或“food” |
[xyz] | 字符集合。匹配所包含的任意一个字符。例如,“[abc]”可以匹配"plain"中的“a”。 |
[^xyz] | 负值字符集合。匹配未包含的任意字符。例如,“[^abc]”可以匹配“plain”中的“p”,“l”,“i”,“n”。 |
[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和\cl。 |
\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) |
\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 匹配版权符号 (?)。 |
运算符优先级
正则表达式从左到右进行计算,并遵循优先级顺序,这与算术表达式非常类似。
相同优先级的从左到右进行运算,不同优先级的运算先高后低。下表从最高到最低说明了各种正则表达式运算符的优先级顺序:
运算符 | 描述 |
\ | 转义符 |
(),(?:),(?=),[] | 圆括号和方括号 |
*,+, ?,{n},{n,},{n, m} | 限定符 |
^,$,\任何元字符,任何元字符 | 定位点和序列(即:位置和顺序) |
| | 替换,“或”操作 字符具有高于替换运算符的优先级,使得m|food匹配“m”或“food”。若要匹配“mood”或“food”,请使用括号创建子表达式。从而产生,“(m|f)ood”。 |
正则表达式-匹配规则
基本模式匹配
一切从最基本的开始。模式,是正则表达式最基本的元素,它们是一组描述字符串特征的字符。模式可以很简单,由普通的字符串组成,也可以非常复杂,往往用特殊字符表示一个范围内的字符、重复出现,或表示上下文。例如:
^once
这个模式包含一个特殊的字符^,表示该模式只匹配那些once开头的字符串。例如该模式与字符串“once upon a time”匹配,与“There once was a man from New York”不匹配。正如^符号表示开头一样,$符号用来匹配那些以给定模式结尾的字符串。
bucket$
这个模式与“Who kept all of his cash in a bucket”匹配,与“buckets”不匹配。字符^和$同时使用时表示精确匹配(字符串与模式一样)。例如
^bucket$
只匹配字符串“bucket”。如果一个模式不包含^和$,那么它与任何包含该模式的字符串匹配。例如,模式
once
与字符串“There once was a man from New York. Who kept all his cash in a bucket.”是匹配的。
在该模式中的字母o-n-c-e是字面的字符,也就是说,他们表示该字符本身,数字也是一样的。其他一些稍微复杂的字符,如标点符号和白字符(空格、制表符等),要用到转义序列。所有的转义序列都用反斜杠打头。制表符的转一序列是\t。所以我们要检测一个字符串是否以制表符开头,可以用这个模式
^\t
类似的,用\n表示新行,\r表示回车。其它的特殊符号,可以用前面加上反斜杠,如斜杠本身用\\表示,句号.用\.表示,以此类推。
字符簇
在INTERNET的程序中,正则表达式通常用来验证用户的输入。当用户提交一个FORM之后,要判断输入的电话号码、地址、EMAIL地址、信用卡号码等是否有效,用普通的基于字面的字符是不够的。
所以要用一种更自由的描述我们要的模式的办法,它就是字符簇。要建立一个表示所有元音字符的字符簇,就把所有的元音字符放在一个方括号里:
[AaEeIiOoUu]
这个模式与任何元音字符匹配,但只能表示一个字符。用连字号可以表示一个字符的范围,如:
[a-z] //匹配所有的小写字母
[A-z] //匹配所有的大写字母
[a-zA-Z] //匹配所有的字母
[0-9] //匹配所有的数字
[0-9\.\-] //匹配所有的数字,句号和减号
[ \f\r\t\n] //匹配所有的白字符
同样的,这些也只表示一个字符,这是一个非常重要的一点。如果要匹配一个由一个小写字符和一位数字组成的字符串,比如“z2”、“t6”或“g7”,但不是“ab2”、“r2d3”或“b52”的话,用这个模式:
^[a-z][0-9]$
尽管[a-z]代表26个字母的范围,但在这里只能与第一个字母是小写字母的字符串匹配。
前面曾经提到^表示字符串的开头,但它还有另外一个含义。当在一个方括号里使用^时,它表示“非”或“排除”的意思,常常用来剔除某个字符。还用前面的例子,我们要求第一个字符不能是数字:
^[^0-9][0-9]$
这个模式与“&5”、“g7”及“-2”是匹配的,但与“12”、“66”是不匹配的。下面几个排除特定字符的例子:
[^a-z] //除了小写字母以外的所有字符
[^\\\/\^] //除了(\)(/)(^)之外的所有字符
[^\'\"] //除了双引号和单引号之外的所有字符
特殊字符.(点,句号)在正则表达式中用来表示除了“新行”之外的所有字符。所以模式“^.5$”与任何两个字符的、以数字5结尾和其它非“新行”字符开头的字符串匹配。模式“.”可以匹配任何字符串、除了空串和只包含一个“新行”的字符串。
PHP正则表达式有一些内置的通用字符簇,列表如下:
字符簇 | 描述 |
[[:alpha:]] | 任何字符 |
[[:digit:]] | 任何数字 |
[[:alnum:]] | 任何字母和数字 |
[[:space:]] | 任何空白字符 |
[[:upper:]] | 任何大写字母 |
[[:lower:]] | 任何小写字母 |
[[:punct:]] | 任何标点符号 |
[[:xdigit:]] | 任何十六进制数字,相当于[0-9a-fA-f] |
确定重复出现
到现在为止你已经知道如何去匹配一个字母或者数字,但更多的情况下你可能要匹配一个单词或者一组数字。一个单词由若干个字母组成,一组数字由若干个单数组成。跟在字符或字符簇后面的花括号({})用来确定前面的内容的重复出现的次数。
字符簇 | 描述 |
^[a-zA-Z_]$ | 所有的字母和下划线 |
^[[:alpha:]]{3}$ | 所有的3个字母的单词 |
^a$ | 字母a |
^a{4}$ | aaaa |
^a{2,4}$ | aa, aaa或aaaa |
^a{1,3}$ | a, aa或aaa |
^a{2,}$ | 包含多于两个a的字符串 |
^a{2,} | aa开头的字符串 |
a{2,} | 包含aa的字符串 |
\t{2} | 两个制表符 |
.{2} | 所有的两个字符 |
这些例子描述了花括号3种不同用法。一个数字{x}的意思是前面的字符或字符簇只出现x次;一个数字加逗号{x,}的意思是前面的内容出现x或更多的次数。两个用逗号分隔的数字{x,y},表示前面的内容至少出现x次,但不超过y次。我们可以把模式扩展到更多的单词和数字。
^[a-zA-Z0-9_]{1,}$ //所有包含一个字母、数字或下划线以上的字符串
^[1-9][0-9]{0,}$ //所有的正整数
^\-{0,1}[0-9]{1,}$ //所有的整数
^[-]?[0-9]+(\.[0-9]+)?$ //所有的浮点数
最后一个例子不大好理解,是吧?这么看吧:以一个可选的负号开头(^[-]?),跟着一个或者更多的数字([0-9]+)和一个小数点(\.)再跟上一个或多个数字([0-9]+$)结尾。