参考资料:
基本概念
正規表現(せいきひょうげん、英: regular expression)形式言語分野
用于文本内容的查找和替换(差し替える)
用于其他语言或者产品软件里面
在使用的时候一定要注意转义符号\,不使用这个符号的时候代表的是真实的内容,使用了才有相应的意思
正则字符
元符号
- 被匹配的字符第一个必须和^之后的一样,最后一个必须和$之前的一样
- “^”:
- 匹配行或字符串的起始位置
- 整个文档的起始位置
$:行或者字符串的结尾
\b:用于匹配边界,不消耗字符(Boundary)
- \bis\b 用来识别is的两边是否是边界
- \d:匹配数字(digit)
- 比如0开头,五位数-> ^0\d\d\d\d\d$
- \w:匹配字母,数字,下划线(基本可以理解为注册用户名的要求)
- \s:匹配空格,\s+可以让空格重复
- .:匹配除了转行符号以外的任何字符。\w的加强版,相当于w加上空格
- []:匹配在空号内元素的字符,只匹配存在于括号里面的。可以写成[a-z]
反义
上面的表达写成大写,如果是[]的话变成[^],表达的意思是不包括这些的字符
量词
有关量词的三个概念:
- 贪心 * 会首先匹配整个字符串,会选择尽可能多的内容,失败的话就backtracking(消耗最大)
- 懒惰 ?从起始位置开始尝试匹配,每次检查一个内容,直到检查完所有的内容(相当于遍历)
- 占有 + 覆盖整个字符串,然后寻找。但是就试一次
相关量词:
- 贪心* 会重复0次或者更多
- ”aaaaa“里面匹配a* ,那么得到的是所有的字符a
- 重复一次或多次:
- ”aaaaa“,a+会取字符中所有a值,但是* 可以是0次,+不行
- 重复一次或多次:
- ? 重复零次或一次
- ”aaaaa“,a?只会匹配一次,结果也是单个字符a
- {n},重复n次,比如a{3}会匹配aaa
- {n,m} 重复n-m次,比如a{3,4}可以匹配到aaa或者aaaa
- {n,} 重复n次或更多次,也就是至少重复n次
懒惰限定符(大家和?的排列组合)
- *? 重复任意次,但是尽可能少重复
- 比如 acbacb,正则 a.*?b,只会匹配acb,因为需要.重复的数量尽可能少
- +?重复1次或者更多次,但是尽可能少重复
- ?? 重复0次或一次,但是尽可能少重复
- {n,m}重复n-m次,但是尽可能少重复。比如a{0,m}?取到的是空
- {n,}?至少重复n次,尽可能少重复
进阶
捕获分组
如果给一部分的内容加上了括号,这部分的内容就被抓住了。然后如果后面用到了相同内容的表达式,就可以直接用一个符号代替,而不用继续写一个了。
不考虑重复使用的时候,也可以单独只用于分组,分组之后的内容可以加上+ * ?等内容进行重复。但是注意嵌套层数过多会引起歧义
常用写法
- (exp):匹配exp。捕获到自动命名的组里面,\1这样的
- (?
exp)匹配exp,捕获内容并自己命名,后面引用的时候需要 “\k “ - (?:exp):匹配exp,但是不捕获,也不给这个组分配编号
- (?=exp):匹配exp前面的位置
- how are you doing,正则(?
.+(?=ing)),去ing前面的字符,匹配出来的是how are you do(匹配ing之前的.+)
- how are you doing,正则(?
- (?<=exp):匹配后面的位置。比如(?
(?<=how).+),匹配后面的位置,也就是匹配how之后的.+ - (?!exp):匹配后面不跟着exp的位置。比如\d{3}(?!\d)匹配三个数字,然后后面不再跟数字了
- (?<!exp):匹配前面不是exp的位置。(?!<[0-9])123,匹配123,并且123前面不能是数字
例子:
分组使用
比如匹配IP地址,IP地址由四部分组成,每一部分是0-255的数字。则可以分为以下的部分表示
- 一位数字
- 不以0开头的两位数
- 2开头,第二位是0-4的三位数
- 25开头,第三位是0-5的三位数
1
((25[0-5]|(2[0-4]\d)|(1\d{2})|([1-9]\d)|(\d))\.){3}(25[0-5]|(2[0-4]\d)|(1\d{2})|([1-9]\d)|(\d))
回溯引用
比如匹配HTML里面的标题元素1
<(h[1-6])>\w*?<\/\1>
其中,h[1-6]被分为一组,这一组的名字叫做\1,也就是说前后的两部分需要一样。h1对h1,h2对h2才能匹配上
替换(需要两个regexp)
比如修改电话号码格式
313-555-1234
- 查找的正则式
(\d{3})(-)(\d{3})(-)(\d{4})
- 需要替换成为的格式
($1)$3-$5
。也就是说把第一个正则式中的第1,3,5个括号直接代入了后面替换的格式里面 - 替换之后的内容 (313)555-1234
大小写转变
- \l 把后面跟随的单独的字符改成小写
- \u 把单独的字符改成大写
- \L 把L之后,E之前的全都变成小写
- \U 把U之后,E之前的全都变成大写
- \E 结束符号
如,abcd,查找(\w)(\w{2})(\w)
,然后改为$1\U$2\E$3
前后查找
订好了应该匹配的内容的首尾内容,但是不包括这个首尾内容。也就是前面说到的向前匹配?=和向后匹配?<=.(但是js不支持向后匹配)。如果要找非的条件的时候,需要把=换成!
- 比如匹配邮箱的@前面的部分
(\w+|.)+(?=@)
(这里加上了.,因为我的学校邮箱@前面也是有. 的) - 匹配结果: **xu.r.aa**@m.titech.ac.jp
嵌入条件
回溯引用
判断某个表达式是否匹配,如果匹配的话继续匹配后面的条件1
(\()?abc(?(1)\))
- 先匹配左括号((),?来判断左括号有0个或者1个
- ?(1)是判断的表达式,也就是说能匹配到左括号的时候,再匹配右括号。
- 匹配结果:
abc
(abc)
(abc
前后查找
条件为首尾是否匹配,如果匹配的话继续(注意首尾不包括在匹配内容里面)1
\d{5}(?(?=-)-\d{4})
- 首先匹配五位数字
- (?=-)表示向前查找-,也就是对-向前查找,作为条件。如果向前查找成功了,那么继续进行后面的操作,也就是匹配一个-,然后匹配一个4位数字
44444-4444
44444-
66666