头部背景图片
吉水于人的笔记 |
吉水于人的笔记 |

正则表达式化整为零

前言

写代码也有一段时间了,正则表达式是经常会用得到,每次遇到一些匹配时,就上网找,因为自己一直都在排斥学正则表达式,但是拖着不是程序猿的好习惯,那今天就来好好整理下。不求全部学会,只求见到认识。
正则表达式常用的几种操作方法有:match、search、split、findall、sub、replace。

基本字符

特殊字符
特殊字符就是具有特殊含义的字符。在正则表达式中,这些特殊字符匹配的意义各有不同,如果需要在字符串中查找这些特殊符号,就需要在其前面加一个\进行转义。

特殊字符 含义
$ 匹配输入字符串的结尾
() 标记一个子表达的开始和结束位置
* 匹配前面的表达式零次或多次
+ 匹配前面的子表达式一次或多次
. 匹配除换行符\n 之外的任何单字符
[ 标记一个中括号表达式的开始
匹配前面的子表达式零次或一次
\ 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符
^ 匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合
{ 标记限定符表达式的开始
指明两项之间的一个选择

贪婪和非贪婪
在上表中列举的*+限定符都是贪婪的,因为它们会尽可能多的匹配文字,只有在它们的后面加上一个?就可以实现非贪婪或最小匹配。

定位符
定位符用来描述字符串或单词的边界,其中^$分别指字符串的开始与结束,\b 描述单词的前或后边界,\B表示非单词边界。

Tip:不能将限定符和定位符一起使用。

带反斜杠的元字符
普通字符前加反斜杠还是普通字符,但是有些字符加上反斜杠之后就会变成元字符

语法

1.检索字符
我们既可以检索普通字符也可以检索表情符号,因为表情符其实也是一个字符,使用match方法可以返回一个数组,包含检索字符内容,被检索到到索引号。

'hello world'.match(/w/);
> ["w", index: 6, input: "hello world", groups: undefined]

'hello 😀world'.match(/😀/);
> ["😀", index: 6, input: "hello 😀world", groups: undefined]

2.匹配文本开始和结束
我们用^匹配文本的开始,用$匹配文本的结束。匹配文本的第一个字符时,必须是匹配文本的第一个字符,否则匹配不成功。

'hello'.match(/^h/);
> ["h", index: 0, input: "hello", groups: undefined]

'hello'.match(/a^h/);
> null

'hello'.match(/o$/);
> ["o", index: 4, input: "hello", groups: undefined]

3.元字符

元字符 含义
\b 匹配一个单词边界
\B 匹配一个非单词边界
\d 匹配一个数字字符
\D 匹配一个非数字字符
\s 匹配一个空白字符
\S 匹配一个非空白字符
\w 匹配一个字母或一个数字或一个下划线
\W 匹配一个字母、数字和下划线之外的字符

元字符上述表格中已列举出来了,元字符的大写相当于取反。匹配单词边界的对中文边界是无效的。

// \b 匹配单词边界
'hello world'.match(/\bworld$/);
> ["world", index: 6, input: "hello world", groups: undefined]

'你 好'.match(/\B好$/);
["好", index: 2, input: "你 好", groups: undefined]

// \d 匹配数字边界
'123'.match(/\d2/);
["12", index: 0, input: "123", groups: undefined]

// \s匹配单个空白字符
'a b'.match(/\s/);
[" ", index: 1, input: "a b", groups: undefined]

// \w匹配单个字母数字下划线
'a b'.match(/\w/);
["a", index: 0, input: "a b", groups: undefined]

4.量词
限定符用来指定正则表达式的一个给定组件必须要出现多次才能匹配

字符 描述
* 匹配前面的子表达式零次或多次
+ 匹配前面的子表达式一次或多次
匹配前面的子表达式零次或一次
{n} n是一个非负整数。匹配确定的n次
{n,} 至少匹配n次
{n,m} n<=m,最少匹配n次最多匹配m次
// 非贪婪模式
'https'.match(/http(s)?/);
["https", "s", index: 0, input: "https", groups: undefined]

'gooooogle'.match(/go{2,5}gle/);
["gooooogle", index: 0, input: "gooooogle", groups: undefined]

5.字符组
方括号在正则中表示一个区间,我们称之为字符组。

'grey or gray'.match(/gr[ae]y/);
["grey", index: 0, input: "grey or gray", groups: undefined]

6.捕获组和非捕获组[ES2018]
圆括号的意思是将它其中的字符集合打包成一个整体,然后量词就可以操作这个整体了。

'i love you very very very much'.match(/i love you (very )+much/);
["i love you very very very much", "very ", index: 0, input: "i love you very very very much", groups: undefined]

7.正则内捕获
正则内捕获使用\数字的形式根据对应前面的圆括号捕获内容,这种捕获的引用也称为反向引用。

'<span>hello world</span>'.match(/<([a-zA-Z]+)>.*<\/\1>/);
> ["<span>hello world</span>", "span", index: 0, input: "<span>hello world</span>", groups: undefined]

8.正则外捕获

'hello **world**'.replace(/\*{2}(.*)\*{2}/, '<strong>$1</strong>');
"hello <strong>world</strong>"

9.非捕获组
当我们需要匹配捕获组,但是又不需要捕获组结果时,我们可以使用非捕获组(?:pattern)

'industry'.match(/industr(?:y|ies)/);
["industry", index: 0, input: "industry", groups: undefined]

10.或

'aA'.match(/a|A/);
["a", index: 0, input: "aA", groups: undefined]

11.零宽断言
零宽断言
零宽:匹配一个位置,本身没有宽度;断言:断言之前或者之后应该有什么或没有什么
(1)零宽肯定先行断言(?=)[正向肯定预查]

'TypeScript JavaScript javascript'.match(/\b\w{4}(?=Script\b)/);
["Type", index: 0, input: "TypeScript JavaScript javascript", groups: undefined]

(2)零宽肯定后行断言(?<=)[ES2018] [反向肯定预查]

'演员高圆圆 将军霍去病 演员霍思燕'.match(/(?<=演员)霍\S+/);
["霍思燕", index: 14, input: "演员高圆圆 将军霍去病 演员霍思燕", groups: undefined]

(3)零宽否定先行断言(?!)[正向否定预查]
否定就是没有,就是要求一段文本,后面一定不要紧跟一段指定文本

'TypeScript Perl JavaScript'.match(/\b\w{4}(?!Script\b)/);
["Perl", index: 11, input: "TypeScript Perl JavaScript", groups: undefined]

(4)零宽否定后行断言(?<!)[ES2018] [反向否定预查]
要求一段文本,前面一定不跟某一段指定文本

'演员高圆圆 将军霍去病 演员霍思燕'.match(/(?<!演员)霍\S+/);
["霍去病", index: 8, input: "演员高圆圆 将军霍去病 演员霍思燕", groups: undefined]

12.修饰符
(1)g修饰符(global)

默认情况下,正则从左向右匹配,只要匹配到结果就会结束,g修饰符会开启全局匹配模式,找到所有的匹配结果
(2)i修饰符(ignoreCase)
默认情况话,正则是区分大小写的,i修饰符的作用是可以全局忽略大小写.
(3)m修饰符(multiline)
默认情况下,^和$匹配的是文本的开始和结束,加上m修饰符,它们的含义就变成了多行的行首和行尾,支持多行搜索
(4)y修饰符(sticky粘连)[ES6]
y修饰符有和g修饰符重合的功能,它们都是全局匹配,不同在于,g修饰符只要剩余位置中存在匹配就可,而y修饰符确保匹配必须从剩余的第一个位置开始,这也就是“粘连”的涵义

'a bag with a tag has a mag'.match(/\wag/g);
["bag", "tag", "mag"]

'a bag with a tag has a mag'.match(/\wag/y);
null

'bagtagmag'.match(/\wag/y);
["bag", index: 0, input: "bagtagmag", groups: undefined]

'bagtagmag'.match(/\wag/gy);
["bag", "tag", "mag"]

(5)s修饰符(singleline)[ES2018]
s修饰符的作用是让.可以匹配任意单个字符。
(6)u修饰符(unicode)[ES6]
有些Unicode字符超过一个字节,正则无法正确识别,可用u修饰符来处理。

ES6变化

ES6中,将字符串的4个正则方法(match,replace,search,split)在语言内部全部调用RegExp的实例方法,从而做到所有与正则相关的方法,全部定义在RegExp对象上。