跳转至

正则表达式info

前言

正则表达式一直是困扰很多程序员的一门技术。作为程序开发者,有必要好好了解一下正则,因为很多问题都可以通过一条简单的正则表达式解决,避免写大量脚本去实现。希望这次分享能帮助大家掌握基础的正则,揭开正则表达式各种符号的神秘面纱,从此走上正则大神之路!

句子

1
2
3
4
5
# 查询没有linuxserver 这个单词的行  (?!...) 断言给定的子表达式在当前位置不能匹配,不消耗字符。
^(?!linuxserver\b).*

# (?<!...) 断言给定的子表达式在当前位置从右往左不能匹配,表达式必须为固定长度。不消耗字符。
/(?<!not )foo/    ||   not foo but foo  只匹配第二个foo

常见正则:

正则表达式基础

原子是正则表达式的最基本组成单位,而且必须至少要包含一个原子。

正则   意思 说明
. 匹配除换行符以外的任意字符 加/s表示所有字符
\d 匹配一个数字字符 等价于 [0-9]
\D 匹配一个非数字字符 等价于 [^0-9]
\w 匹配包括下划线的任何单词字符 等价于[A-Za-z0-9_]
\W 匹配任何非单词字符 等价于[^A-Za-z0-9_]
\s 匹配任何空白字符,包括空格、制表符、换页符等等 等价于[\f\n\r\t\v\u000B\u0020\u00A0\u2028\u2029]
\S 匹配任何非空白字符 等价于 [^ \f\n\r\t\v]
\n 匹配一个换行符 等价于 \x0a 和 \cJ
\f 匹配一个换页符 等价于 \x0c 和 \cL
\r 匹配一个回车符 等价于 \x0d 和 \cM
\t 匹配一个制表符 等价于 \x09 和 \cI
\v 匹配一个垂直制表符 等价于 \x0b 和 \cK
\xxx 匹配八进制规定的ASCII编码字符 比如[0-9]可写成[\48-\57]
\xdd 匹配十六进制规定的ASCII编码字符 比如[0-9]可写成[\x30-\x39]
\uxxxx 匹配十六进制规定的Unicode字符 比如[0-9]可写成[\u0030-\u0039]

[abc],表示a或者b或者c中的任意一个字符; [a-z]、[A-Z]、[0-9],表示小写字母,大写字母,0到9的数字; [a-z]、[A-Z]、[^0-9],表示非小写字母,非大写字母,非0到9的数字;

更多参见基本多语言面(Basic Multilingual Plane,BMP)详细信息 基本多文种平面

分枝条件指的是有几种规则,如果满足其中任意一种规则都应该当成匹配,方法是用|把不同的规则分隔开。

"aababxb".replace(/a|b/g,'')

正则 说明
{m} 表示前面的原子必须出现m次
{m,} 表示前面的原子最少出现m次
{m,n} m要小于n,表示前面出现的原子,最少m次,最多n次,包括m和n次
? 等价{0,1}表示其前面的原子可以出现0次或1次,有只能有一次,要么没有
+ 等价{1,}表示其前的原子可以出现1次或多次,不能没有最少要有一个
* 等价{0,}表示其前的原子可以出现0次、1次、或多次

当正则表达式中包含能接受重复的限定符时,通常的行为是匹配尽可能多的字符。

"aababxb".match(/a.*b/);//贪婪匹配 返回aababxb
"aababxb".match(/a.*?b/);//懒惰匹配 返回aab
它将会匹配整个字符串。这被称为贪婪匹配。

代码/语法 说明
{n,}? 重复n次以上,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
*? 重复任意次,但尽可能少重复

位置可以理解为相邻字符之间的位置。咱们可以和空字符串进行类比, 字符的首尾、间隙都可以用空字符串进行连接。

'hello' === '' + 'h' + '' + 'e' + '' + 'l' + '' +  'l' + '' + 'o' + ''

符号 说明
^ 脱字符,有m时是行的开头,无m是字符串的开始
$ 美元符,有m时是行的末尾,无m是字符串的结束
\b 单词的边界,具体讲有三点规则:①\w和\W之间的位置 ②^与\w之间的位置 ③\w与$之间的位置
\B 非单词的边界,与上面相反:①\w与\w之间的位置 ②\W与\W之间的位置 ③^与\W之间的位置 ④\W与$之间的位置
\A 文本开头
\Z 文本结尾

用小括号来指定子表达式(也叫做分组)。

代码/语法 说明
(exp) 匹配exp,并捕获文本到自动命名的组里
(?:exp) 匹配exp,不捕获匹配的文本,也不给此分组分配组号
(?\<name>exp) 匹配exp,并捕获文本到名称为name的组里

特殊变量名表:

变量名 说明
$$ 直接量符号,即$字符
$n 第n个子表达式相匹配的文本,n等于[1-9]。等于RegExp.$n
$_ 正则搜索的字符串。等于RegExp.input
$& 正则最后一次匹配的字符串。等于RegExp.lastMatch
$+ 正则最后一个分组内容。等于RegExp.lastParen
$` 正则匹配子串左侧的文本。等于RegExp.leftContext
$’ 正则匹配子串右侧的文本。等于RegExp.rightContext

反向引用(回溯引用)

使用小括号指定一个子表达式后,默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推(等于RegExp.$n)。你可以使用(?:exp)这样的语法来剥夺一个分组对组号分配的参与权。

var reg = /<(\w)>.*?<\1>/  //匹配html标签
var str = 'abc%45,efd%12'.replace(/(%)(\d+)/g,'$2$1') //互换字符

正则表达式断言高级

当我们想要查找类似\b,^,$那样的一个位置,这个位置应该满足一定的条件(即断言),但这个位置并不包含任何内容,我们称之为零宽断言。又称之为环视(lookaround)结构。

零宽断言

代码/语法 说明 名称
x(?=exp)y 断言y部分能匹配exp,与x无关 零宽度正预测先行断言,肯定顺序环视,正向前瞻,正向预查,向前断言
x(?!exp)y 断言y部分不能匹配exp,与x无关 零宽度负预测先行断言,否定顺序环视,负向前瞻,负向预查,向前否定断言
x(?<=exp)y 断言x部分能匹配exp,且exp从右到左匹配,与y无关。ES7支持 零宽度正回顾后行断言,肯定逆序环视,向后断言
x(?<!exp)y 断言x部分不能匹配exp,且exp从右到左匹配,与y无关。ES7支持 零宽度负回顾后发断言,否定逆序环视,向后否定断言

后行断言的特点是从右向左匹配,分组编号虽然一样从左到右分配,但引用时必须在编号的左边引用。

字符转义

\/[\](){}?+*|.^$-
作为字符来匹配必须转义,才能作为正则的原子。

性能

核心:减少“回溯”次数,尽快匹配结果:
- 1、尽量使用边界符(^、$、\b、\B等),限定搜索字符串位置
- 2、使用具体的元字符(\d、\w、\s等),少用”.”字符
- 3、多使用确定的量词({n}、{n,m}),少用贪婪匹配
- 4、减少分支,减少“回溯”

正则辅助网站

在线正则:https://regex101.com/

可视化正则:https://jex.im/regulex

可视化正则:https://regexper.com/

可视化正则:https://www.debuggex.com/