正则表达式学习
1、 常用的元字符
. |
匹配除换行符以外的任意字符 |
\w |
匹配字母或数字或下划线,[a-zA-Z0-9] |
\s |
匹配任意的空白符,[\t\n\r\f] |
\d |
匹配数字,[0-9] |
\b |
匹配单词的开始或结束 |
^ |
匹配字符串的开始 |
$ |
匹配字符串的结束 |
2、 常用的反义代码
\W |
与\w相反,[^a-zA-Z0-9] |
\S |
与\s相反,[^\t\n\r\f] |
\D |
与\d相反,[^0-9] |
\B |
匹配不是单词开头或结束的位置 |
[^aeiou] |
匹配除了aeiou这几个字母以外的任意字符 |
3、 常用的限定符
* |
重复零次或更多次 |
+ |
重复一次或更多次 |
? |
重复零次或一次 |
{n} |
重复n次 |
{n,} |
重复n次或更多次 |
{n,m} |
重复n到m次 |
4、 后向引用
使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则如下:
l 分组0对应整个正则表达式;
l 从左向右扫描两遍,第一遍只给未命名组分配,第二遍只给命名组分配;
l 可以使用(?:exp)这样的语法来剥夺一个分组对组号分配的参与权。
后向引用用于重复搜索前面某个分组匹配的文本,例如,\1代表分组1匹配的文本。\b(\w+)\b\s+\1\b可以用来匹配重复的单词,像go go, 或者kitty kitty。这个表达式首先是一个单词,也就是单词开始处和结束处之间的多于一个的字母或数字(\b(\w+)\b),这个单词会被捕获到编号为1的分组中,然后是1个或几个空白符(\s+),最后是分组1中捕获的内容(也就是前面匹配的那个单词)(\1)。
也可以自己指定子表达式的组名(?'Word'\w+),这样就把\w+的组名指定为Word了,要反向引用这个分组捕获的内容,你可以使用\k'Word',所以上一个例子也可以写成这样:\b(?'Word'\w+)\b\s+\k'Word'\b。
5、 常用分组语法
捕获 |
(exp) |
匹配exp,并捕获文本到自动命名的组里 |
(?<name>exp) |
匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp) |
|
(?:exp) |
匹配exp,不捕获匹配的文本,也不给此分组分配组号 |
|
零宽断言 |
(?=exp) |
匹配exp前面的位置 |
(?<=exp) |
匹配exp后面的位置 |
|
(?!exp) |
匹配后面跟的不是exp的位置 |
|
(?<!exp) |
匹配前面不是exp的位置 |
|
注释 |
(?#comment) |
不对正则表达式的处理产生任何影响,用于提供注释让人阅读 |
6、 零宽断言
零宽断言用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像\b,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言)。正则表达式中只有当断言为真时才会继续进行匹配。
(?=exp)也叫零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp。比如\b\w+(?=ing\b),匹配以ing结尾的单词的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing时,它会匹配sing和danc。
(?<=exp)也叫零宽度正回顾后发断言,它断言自身出现的位置的前面能匹配表达式exp。比如(?<=\bre)\w+\b会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading a book时,它匹配ading。
一个复杂的例子:(?<=<(\w+)>).*(?=<\/\1>)匹配不包含属性的简单HTML标签内里的内容。
要包含注释的话,最好是启用“忽略模式里的空白符”选项,这样在编写表达式时能任意的添加空格,Tab,换行,而实际使用时这些都将被忽略。启用这个选项后,在#后面到这一行结束的所有文本都将被当成注释忽略掉。例如,可以前面的一个表达式写成这样:
(?<= # 断言要匹配的文本的前缀
<(\w+)> # 查找尖括号括起来的字母或数字(即HTML/XML标签)
) # 前缀结束
.* # 匹配任意文本
(?= # 断言要匹配的文本的后缀
<\/\1> # 查找尖括号括起来的内容:前面是一个"/",后面是先前捕获的标签
) # 后缀结束
7、 贪婪与懒惰
当正则表达式中包含能接受重复的限定符时,通常的行为是在使整个表达式能得到匹配的前提下匹配尽可能多的字符。以这个表达式为例:a.*b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。
a.*?b匹配最短的,以a开始、以b结束的字符串。如果把它应用于aabab的话,它会匹配aab(第一到第三个字符)和ab(第四到第五个字符)。正则表达式有另一条规则,比懒惰/贪婪规则的优先级更高: The match that begins earliest wins。
*? |
重复任意次,但尽可能少重复 |
+? |
重复1次或更多次,但尽可能少重复 |
?? |
重复0次或1次,但尽可能少重复 |
{n,m}? |
重复n到m次,但尽可能少重复 |
{n,}? |
重复n次以上,但尽可能少重复 |
8、 平衡组递归匹配
有时需要匹配像<100*<50+15>>这样的可嵌套的层次性结构,这时简单地使用<.+>则只会匹配到最左边的左括号和最右边的右括号之间的内容(这里我们讨论的是贪婪模式,懒惰模式也有下面的问题)。假如原来的字符串里的左括号和右括号出现的次数不相等,比如<5/<3+2>>>,那我们的匹配结果里两者的个数也不会相等。能不能把最长的配对的尖括号内的内容捕获出来?
(?'group') |
把捕获的内容命名为group,并压入堆栈(Stack) |
(?'-group') |
从堆栈上弹出最后压入堆栈的名为group的捕获内容,如果堆栈本来为空,则本分组的匹配失败 |
(?(group)yes|no) |
如果堆栈上存在以名为group的捕获内容的话,继续匹配yes部分的表达式,否则继续匹配no部分 |
(?!) |
零宽负向先行断言,由于没有后缀表达式,试图匹配总是失败 |
我们需要做的是每碰到了左括号,就在压入一个"Open",每碰到一个右括号,就弹出一个,到了最后就看看堆栈是否为空,如果不为空那就证明左括号比右括号多,那匹配就应该失败。正则表达式引擎会进行回溯(放弃最前面或最后面的一些字符),尽量使整个表达式得到匹配。
< #最外层的左括号
[^<>]* #最外层的左括号后面的不是括号的内容
(
(
(?'Open'<) #碰到了左括号,入堆栈"Open"
[^<>]* #匹配左括号后面的不是括号的内容
)+
(
(?'-Open'>) #碰到了右括号,出堆栈"Open"
[^<>]* #匹配右括号后面不是括号的内容
)+
)*
(?(Open)(?!)) #在遇到最外层的右括号前面,判断堆栈中是否有Open,如果还有,则匹配失败
> #最外层的右括号
平衡组的一个最常见的应用就是匹配HTML,下面这个例子可以匹配嵌套的<div>标签:<div[^>]*>[^<>]*(((?'Open'<div[^>]*>)[^<>]*)+((?'-Open'</div>)[^<>]*)+)*(?(Open)(?!))</div>。
9、 常用正则表达式
网址(URL) |
[a-zA-z]+://[^\s]* |
IP地址 |
((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?) |
电子邮件 |
\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)* |
QQ号码 |
[1-9]\d{4,} |
HTML标记(包含内容或自闭合) |
<(.*)(.*)>.*<\/\1>|<(.*) \/> |
密码(由数字/大写字母/小写字母/标点符号组成,四种都必有,8位以上) |
(?=^.{8,}$)(?=.*\d)(?=.*\W+)(?=.*[A-Z])(?=.*[a-z])(?!.*\n).*$ |
日期(年-月-日) |
(\d{4}|\d{2})-((0?([1-9]))|(1[1|2]))-((0?[1-9])|([12]([1-9]))|(3[0|1])) |
日期(月/日/年) |
((0?[1-9]{1})|(1[1|2]))/(0?[1-9]|([12][1-9])|(3[0|1]))/(\d{4}|\d{2}) |
时间(小时:分钟,24小时制) |
((1|0?)[0-9]|2[0-3]):([0-5][0-9]) |
汉字(字符) |
[\u4e00-\u9fa5] |
中文及全角标点符号(字符) |
[\u3000-\u301e\ufe10-\ufe19\ufe30-\ufe44\ufe50-\ufe6b\uff01-\uffee] |
中国大陆固定电话号码 |
(\d{4}-|\d{3}-)?(\d{8}|\d{7}) |
中国大陆手机号码 |
1\d{10} |
中国大陆邮政编码 |
[1-9]\d{5} |
中国大陆身份证号(15位或18位) |
\d{15}(\d\d[0-9xX])? |
非负整数(正整数或零) |
\d+ |
正整数 |
[0-9]*[1-9][0-9]* |
负整数 |
-[0-9]*[1-9][0-9]* |
整数 |
-?\d+ |
小数 |
(-?\d+)(\.\d+)?
|