正则笔记-忘记就来看
如果想知道正则在js中的应用可移步:JS中的正则应用
选项(attributes)
js中的正则表达式选项:
- i 忽略大小写
- m 处理多行
- g 全局匹配(查找所有匹配而非在找到第一个匹配后停止)。
元字符(特殊代码)
字符:是计算机软件处理文字时最基本的单位,可能是字母,数字,标点符号,空格,换行符,汉字等等
匹配字符
\d
一位数字\D
任意非数字的字符\w
字母或数字或下划线\W
任意不是字母,数字,下划线的字符\n\r
其中\r
回车,\n
换行符\s
任意的空白符,包括空格,制表符(Tab),换行符,中文全角空格等\S
任意不是空白符的字符.
查找单个字符,除了换行和行结束符。
注意:js中
\w
匹配不到汉字,在其他语言中有能匹配到汉字的
范围,指定这个范围中的一个字符
[aeiou]
里面单个字符是或的关系[^aeiou]
除了aeiou这几个字母以外的任意字符[0-9]
指这个范围中的一个,相当于\d[^x]
除了x以外的任意字符
量词,指定它前边的内容出现的次数,加了量词时正则会表现出贪婪匹配的特性
?
重复0次或1次(表示有或没有),用在量词后面表示尽可能少重复,切换了懒惰匹配的特性+
重复1次或更多次*
连续重复使用任意次(它代表的不是字符,也不是位置,而是数量){n}
重复n次{n,m}
连续重复n-m次{n,}
重复n次或更多次
其他
\b
匹配单词的开始或结束
虽然通常英文的单词是由空格,标点符号或者换行来分隔的,但是\b并不匹配这些单词分隔字符中的任何一个,它只匹配一个位置。\B
不是单词开头或结尾的位置^
匹配字符串的开始([^]这里表示除了的意思)$
匹配字符串的结束 这两个和\b
类似,都只匹配一个位置- 选项m和^$一起使用时,就变成了匹配行的开始处和结束处,因此在此模式下,$的精确含意是:匹配\n之前的位置以及字符串结束前的位置.
不常用
\t
制表符,Tab\v
竖向制表符(?<x>-<y>exp)
平衡组(?>exp)
贪婪子表达式(?(exp)yes|no)
把exp当作零宽正向先行断言,如果在这个位置能匹配,使用yes作为此组的表达式;否则使用no(?(exp)yes)
同上,只是使用空表达式作为no(?(name)yes|no)
如果命名为name的组捕获到了内容,使用yes作为表达式;否则使用no(?(name)yes)
同上,只是使用空表达式作为no
原文输出需要转译的都是有特殊意义的字符,当然包括所有元字符,但是不包括
-
贪婪与懒惰
a.*b
:它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。
a.*?b
:匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aab(第一到第三个字符)和ab(第四到第五个字符)。这被称为懒惰匹配
为什么第一个匹配是aab(第一到第三个字符)而不是ab(第二到第三个字符)?简单地说,因为正则表达式有另一条规则,比懒惰/贪婪规则的优先级更高:最先开始的匹配拥有最高的优先权
分枝条件(|,又叫或)
正则表达式里的分枝条件指的是有几种规则,如果满足其中任意一种规则都应该当成匹配,具体方法是用|把不同的规则分隔开。使用分枝条件时,要注意各个条件的顺序。匹配分枝条件时,将会从左到右地测试每个条件,如果满足了某个分枝的话,就不会去再管其它的条件了。
分组(())
用法一:重复多个字符
(xxx){num}
用法二:捕获组(分组捕获)
默认情况下,每个分组会自动拥有一个组号
组号分配规则:
- 分组0对应整个正则表达式
- 实际上组号分配过程是要从左向右扫描两遍的:第一遍只给未命名组分配,第二遍只给命名组分配,因此所有命名组的组号都大于未命名的组号
- 你可以使用(?:exp)这样的语法来剥夺一个分组对组号分配的参与权.
- 自定义组号:
(?<Word>\w+)
或(?'Word'\w+)
这样就可以把这个捕获组的组号变成了Word了,再使用反向引用时不能再用\num
这种写法,要使用\k<Word>
才能拿到内容。
常用分组语法:
分类 | 代码/语法 | 说明 |
---|---|---|
捕获 | (exp) |
匹配exp,并捕获文本到自动命名的组里 |
(?<name>exp) |
匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp) | |
(?:exp) |
匹配exp,不捕获匹配的文本,也不给此分组分配组号 | |
零宽断言 | (?=exp) |
(零宽度正预测先行断言)匹配后面跟的是exp的内容 |
(?<=exp) |
(零宽度正回顾后发断言)匹配前面是exp的内容 | |
(?!exp) |
(零宽度负预测先行断言)匹配后面跟的不是exp的内容 | |
(?<!exp) |
(零宽度负回顾后发断言)匹配前面不是exp的内容 | |
注释 | (?#comment) |
这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读 |
反向引用(后向引用,不知道哪个名字对,无奈脸。。。)
反向引用用于重复搜索前面某个分组匹配的文本。要结合捕获组使用
正则表达式中想用num号组捕获到的内容再做匹配时,可以写\num
注意:是捕获到的内容,不是捕获组所用的正则
小栗子
\b(\w+)\b\s+\1\b
,能匹配到 go go , word word , aaa aaa 等,但是无法匹配到 go to
更改组号写法:\b(?<Word>\w+)\b\s+\k<Word>\b
零宽断言
用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像\b,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言。
栗子:(?<=<(\w+)>).*(?=<\/\1>)
用来匹配不包含属性的简单HTML标签内里的内容。
解析:(?<=<(\w+)>)
指定了这样的前缀:被尖括号括起来的单词(比如可能是<b>
),然后是.*
(任意的字符串),最后是一个后缀(?=<\/\1>)
。注意后缀里的\/
,它用到了前面提过的字符转义;\1
则是一个反向引用,引用的正是捕获的第一组,前面的(\w+)
匹配的内容,这样如果前缀实际上是<b>
的话,后缀就是</b>
了。整个表达式匹配的是<b>
和</b>
之间的内容(再次提醒,不包括前缀和后缀本身)。
平衡组/递归匹配
需要匹配可嵌套的层次性结构
语法 | 说明 |
---|---|
(?'group') |
把捕获的内容命名为group,并压入堆栈(Stack) |
(?'-group') |
从堆栈上弹出最后压入堆栈的名为group的捕获内容,如果堆栈本来为空,则本分组的匹配失败 |
(?(group)yes|no) |
如果堆栈上存在以名为group的捕获内容的话,继续匹配yes部分的表达式,否则继续匹配no部分 |
(?!) |
零宽负向先行断言,由于没有后缀表达式,试图匹配总是失败 |
我们需要做的是每碰到了左括号,就在压入一个"Open",每碰到一个右括号,就弹出一个,到了最后就看看堆栈是否为空--如果不为空那就证明左括号比右括号多,那匹配就应该失败。正则表达式引擎会进行回溯(放弃最前面或最后面的一些字符),尽量使整个表达式得到匹配。
平衡组的一个最常见的应用就是匹配HTML,下面这个例子可以匹配嵌套的<div>
标签:<div[^>]*>[^<>]*(((?'Open'<div[^>]*>)[^<>]*)+((?'-Open'</div>)[^<>]*)+)*(?(Open)(?!))</div>
.
好吧,我并不知道怎么用平衡组。。。
小知识
- 加^$则需要输入的整个字符都需要满足所写的正则匹配规则才可以,如果不加则整个字符串中只要有能匹配上规则的部分即可
- ^\w+ 匹配一行的第一个单词(或整个字符串的第一个单词,具体匹配哪个意思得看选项设置)
- [.?!] 匹配标点符号(.或?或!)
- [^.?!] 匹配除了标点符号.或?或!以外的任意字符
本文主要参考文献
- 正则表达式30分钟入门教程:http://deerchao.net/tutorials/regex/regex.htm
- w3school JavaScript RegExp 对象:http://www.w3school.com.cn/jsref/jsref_obj_regexp.asp