正则表达式概述
正则表达式,又叫规则表达式(Regular Expression)。通常被用来检索、替换那些符合某个模式(规则)的文本。正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
简单的说正则表达式是用来定义字符串规则的公式,公式本身也是字符串,其中包括两种字符,一种是普通字符,一种是特殊字符,特殊字符又称为元字符。
许多程序设计语言都支持利用正则表达式进行字符串操作,JavaScript中也可以使用正则表达式。JavaScript中正则表达式是个难点,但使用它却不难,对于常用的正则表达式在网上都能找到,下面仅仅介绍一些语法规则,要写出复杂好用的正则表达式,还需要多多的在实践中反复练习。
本文将使用RegExp 对象的test方法和String对象的match方法和replace方法来验证边界元字符的用法。
正则表达式组成
语法:/正则表达式主体/修饰符(可选)
- 正则表达式主体包含两种字符:
① 普通字符: 包括大小写的字母和数字,普通字符代表其本身含义
② 特殊字符(元字符): 是有特殊含义的非字母字符,包括:* ? $ ^ . | \ () {} [] -,如:\b 匹配边界,\n 换行,\d 数字,\s 空白字符 - 修饰符
修饰符 | 描述 |
---|---|
g | global,表示全文搜索;若不添加g,则搜索到第一个匹配结果即停止匹配 |
i | ignore case,忽略大小写;若不添加i,则默认大小写严格匹配 |
m | multiple lines 执行多行匹配。 |
关于元字符
在这种表达式中,最重要的就是掌握元字符。这里把元字符按照其作用分成几类来掌握。
1、字符“类” (元字符:[ ]和^)
元字符 [ ]
可使用来构建一个简单的类,表达式可以匹配该类的任一字符,如下面的例子中,reg1匹配‘abc’,reg2匹配’a’或‘b’或c。
var reg1=/abc/
var reg2=/[abc]/
reg1.test('abc') //true
reg1.test('b') //false
reg2.test('b') //true
元字符^
可以给字符类取反,含义是不属于某个类的内容。
var reg=/[^abc]/
reg.test('b') //false
reg.test('d') //true
PS:元字符^还有一个作用,用于匹配字符串开头位置,将在后面讲到
2、范围类(元字符:-)
可以使用[0-9]代替[0123456789]提高书写效率,与之类似常用的写法有[0-9]、[a-z]、[A-Z]、[a-zA-Z0-9]
3、预定义类(元字符:. \d \D \s \S \w \W)
预定义类来匹配常见的字符类,可以理解为一些常用的正则表达式的简写形式,常用的预定义类:.、\d、\D、\s、\S、\w、\W
字符 | 等价类 | 含义 |
---|---|---|
. | [^\r\n] | 除了回车、换行符之外的其他字符 |
\d | [0-9] | 数字字符 |
\D | [^0-9] | 非数字字符 |
\s | [\t\n\x0B\f\r] | 空白符 |
\S | [^\t\n\x0B\f\r] | 非空白符 |
\w | [a-zA-Z_0-9] | 单词字符(字母、数字、下划线) |
\W | [^a-zA-Z_0-9] | 非单词字符 |
5、边界
对于字符串而言,边界的意思意味着,字符串的开头和结束、行的开头和结束、单词的开头和结束等
常用的边界匹配字符:^、$、\b、\B
字符 | 含义 |
---|---|
^ | 以xxx开始 |
$ | 以xxx结束 |
\b | 单词边界 |
\B | 非单词边界 |
①元字符^ 在字符类{ ]中表示否定,其他情况下用于限定字符串的开头,如果是多行匹配则是匹配行头
/^0411-/.test('0411-83600000') //true,匹配0411-开头的字符串
'0411-83600000\n0411-83600001'.match(/^0411-/g) //["0411-"],只匹配首行
'0411-83600000\n0411-83600001'.match(/^0411-/gm) // ["0411-", "0411-"],多行匹配
②元字符$,用于限定字符串的结尾或者行尾,写法参考元字符^
'0411-83600011\n0411-83600001'.match(/1$/gm) //["1", "1"]
③ 元字符\b和\B不是很好理解,先说一下单词边界
正则表达式中所谓的“单词”(而非字符),就是由“\w”(字母、数字、下划线)所定义的字符所组成的子串(这等于说中文字符并不是单词)。
验证单词边界的说法,这里先用String对象的match方法来得到单词数量,元字符+表示匹配一次或以上
"Lilian and Lili are pretty girls".match(/\w+/g) //["Lilian", "and", "Lili", "are", "pretty", "girls"]
"Lilian_and_Lili_are_pretty_girls".match(/\w+/g) //["Lilian_and_Lili_are_pretty_girls"]
"Lilian-and-Lili-are-pretty-girls".match(/\w+/g) // ["Lilian", "and", "Lili", "are", "pretty", "girls"]
//单词边界\b 如果要将Lili替换成Lily尝试下面的代码
"Lilian and Lili are pretty girls".replace(/Lili/g,'Lily') //"Lilyan and Lily are pretty girls",没有边界,结果错误
"Lilian and Lili are pretty girls".replace(/\bLili/g,'Lily') //"Lilyan and Lily are pretty girls" ,只有做边界,结果错误
"Lilian and Lili are pretty girls".replace(/\bLili\b/g,'Lily') //"Lilian and Lily are pretty girls",限定了左右单词边界,结果正确
//非单词边界\B 如果要将Lilian替换成Lilyan尝试下面的代码
"Lilian and Lili are pretty girls".replace(/\BLili\B/g,'Lily') //"Lilian and Lili are pretty girls",在上例中将\b改为\B,没有匹配到
"Lilian and Lili are pretty girls".replace(/Lili/g,'Lily') //"Lilyan and Lily are pretty girls"
"Lilian and Lili are pretty girls".replace(/Lili\B/g,'Lily') //"Lilyan and Lili are pretty girls" ,匹配字符Lili并且字符右侧不是单词边界
6、分组符号
分组符号()一般使用在以下场景:
① 使用 () 进行分组,其后跟随的量词作用于分组内的表达式。
'abcabc123456'.replace(/(abc){2}/,'abc') //"abc123456"
② 配合元字符 |,匹配多个子表达式中的一个,分组符号用于提高匹配的优先级
'abcabc123456'.replace(/(123|456)/g,'') //"abcabc"
③ 在javascript中可以使用符号 $,作为变量,捕获并引用分组内的内容
本例中,把月日年格式的字符串转换成年月日格式
"2019-5-30".replace(/(\d{4})-(\d{1,2})-(\d{1,2})/g,'$2-$3-$1') //"5-30-2019"
④协助实现前瞻,负前瞻,后瞻,负后瞻
前瞻,负前瞻,后瞻,负后瞻一般用于替换字符,他们是对要匹配的字符的前、后进行限制,已实现更精确的匹配,常常用于整段文本的内容替换,或者在编辑器中进行批量的修改。
比如我要把前面是数字的px,替换成rem,就可以用后瞻表达式
'1000px'.replace(/(?<=\d+)px/g,'rem') //"1000rem"
表达式 | 名称 | 描述 |
---|---|---|
(?=exp) | 正向前瞻 | 匹配后面满足表达式exp的位置 |
(?!exp) | 负向前瞻 | 匹配后面不满足表达式exp的位置 |
(?<=exp) | 正向后瞻 | 匹配前面满足表达式exp的位置 |
(?<!exp) | 负向后瞻 | 匹配前面不满足表达式exp的位置 |
'a1b2c3'.replace(/\d(?=[a-zA-Z])/g,'8') //"a8b8c3",正前瞻匹配后面是字母的数字
'a1b2c3'.replace(/\d(?!\d)/g,'8') //"a8b8c8",负前瞻匹配后面是不是数字的数字
'a1b2c3'.replace(/(?<=[a-zA-Z])\d/g,'8') //"a8b8c8" ,后瞻,匹配前面是字母的数字
'a1b2c3'.replace(/(?<!\d)\d/g,'8') //"a8b8c8",负后瞻,匹配前面不是数字的数字
PS:正则表达式的前瞻后瞻对于前端来说不仅在js代码中有意义,而且可以在编辑器中对代码进行正则替换
7、分支
元字符 ‘|’ 用于匹配多个子表达式中的一个,子表达式之间是逻辑或的关系。
/com|net|cn$/.test('baidu.com') //true
8、转义
① JavaScript正则表达式也支持非字母的字符匹配,这些字符需要通过反斜杠(\)进行转义
字符 | 含义 |
---|---|
\n | 换行 |
\t | 制表符 |
\v | 垂直制表符 |
\r | 回车符 |
\f | 换页符 |
② 在正则表达式语法中,使用了这么多的元字符代表特殊的意义,那么如果不使用它们的含义,就是想直接使用这些符号,就需要对这些字符进行转义,转义方法很简单,只需要通过反斜杠(\)进行转义
PS:如果忘记哪个字符需要转义了,可以在所有字符上加\进行转义。
9、 匹配次数
在讲匹配次数前,先说一下贪婪模式与非贪婪模式,贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配,而非贪婪模式在整个表达式匹配成功的前提下,尽可能少的匹配。
下表为属于贪婪模式的量词:
符号 | 代表意思 | 使用场景 |
---|---|---|
* | 0次及0次以上 | \d* 匹配数字,123、02、空 |
+ | 1次及1次以上 | \d+ 匹配数字,123、02、3 |
? | 0次或1次 | \d? 匹配数字,2、空 |
{m,n} | m次到n次 | \d{1,3} 匹配数字,2、12、123 |
{n} | n次\d{2} | 匹配数字,12 |
{n,} | n次及n次以上 | \d{2,} 匹配数字,12、123、1234 |
/^[0-9]{6}$/ //邮政编码的正则表达式