JavaScript正则表达式-别再面向搜索引擎编程啦!

1,673 阅读8分钟

前言

本文介绍了对正则表达式的基本使用与总结,希望之后再用到正则时,不再面向搜索引擎编程😃。

首先推荐两个比较好的学习正则的网站:

  1. 在线编辑正则表达式
  2. 胶囊编程正则表达式学习

正则对象方法

方法名描述
exec根据正则查找匹配的字符,返回匹配到的第一个字符的信息所组成的数组(未匹配则返回null
test根据正则查找匹配的字符,匹配成功返回true,否则返回false

exec

使用方法:

const regExp = /h/;

console.log(regExp.exec('hello'));

//[0: "h", groups: undefined, index: 0, input: "hello"]

test

使用方法与exec一样:

const regExp = /h/;

console.log(regExp.test('hello'));

// true

用于正则匹配的String方法

方法名描述
search根据正则查找匹配的字符, 返回第一个匹配的字符的索引,没有匹配到则返回-1.注意:因为search会忽略修饰符g,所以它不支持全局搜索
replace根据正则查找匹配的字符,并且使用替换字符串替换掉匹配到的字符串,返回一个被替换后的新字符串,原字符串不变
match根据正则查找匹配的字符,返回一个由匹配结果组成的数组
split根据正则查找匹配的字符,并根据匹配结果分隔原始字符串,返回一个由被分割后的结果所组成的数组

search

语法:

str.search(regexp) // regexp:正则表达式

使用方式:

const regExp = /h/;
const str = 'elho';

console.log(str.search(regExp)); //返回匹配结果的索引: 2

replace

语法:

str.replace(regexp|substr, newSubStr|function) // regexp:正则表达式

使用方式:

const regExp = /h/;
const str = 'elho';

console.log(str.replace(regExp, 'k')); //elko

match

语法:

str.match(regexp) // regexp:正则表达式

使用:

const regExp = /h/;
const str = 'elho';

console.log(str.match(regExp)); 

// [0: "h", groups: undefined, index: 2, input: "elho"]

当不使用全局模式匹配时,match返回的结果与正则对象的exec方法一样。不同的是,当使用全局模式匹配时,match会返回一个由匹配结果组成的数组,而exec方法始终返回第一个匹配到的字符的信息。

const regExp = /h/g;
const str = 'elhoh';

console.log(str.match(regExp)); // ['h', 'h']
console.log(regExp.exec(str)); // [0: "h", groups: undefined, index: 2, input: "elho"]

split

语法:

str.split(separator|regexp, limit)

regexp:正则表达式

limit: 一个整数,限定返回的分割片段数量,例如:split结果为[1, 2, 3],传入的limit为2,那么只返回结果数组的前面两位,最终返回的结果则为:[1, 2]

使用:

const regExp = /\s?;\s?/g;
const str = 'Harry ;Fred ; Rigby ;';

console.log(str.split(regExp)); // ['Harry', 'Fred', 'Rigby', '']

console.log(str.split(regExp, 1)); // ['Harry']

正则表达式标志

正则表达式有六个可选参数,允许全局和不分大小写搜索等。这些参数既可以单独使用也能以任意顺序组合一起使用。

标志描述
g全局搜索
i不分大小写
m全局搜索
s允许.匹配换行符
u使用unicode编码模式进行匹配
y执行“粘性(sticky)”搜索,匹配从目标字符串的当前位置开始

使用方法

单个使用:

const regExp = /h/g;
const str = 'helho';

console.log(str.match(regExp)); // ['h', 'h']

多个组合使用:

const regExp = /h/gi;
const str = 'helHo';

console.log(str.match(regExp)); // ['h', 'H']

字符类

字符组

字符组([]):允许匹配一组可能出现的字符。

例如:

1638947476748.jpg

[]中放置需要匹配的不同字符:Jj。意思就是需要配置:javaScript或者JavaScript

区间

有些字符组非常大,比如我们需要匹配所有的数字,那么我们的字符组就需要这样写:[0123456789]。需要匹配所有的英文字母,那么我们就必须从a-zA-Z都写一遍,这样的做法十分麻烦,所以正则中可以在[]中使用-符号来代表区间。

  1. 如果我们需要匹配数字,那么使用区间可以这样写:[0-9]
  2. 如果我们需要配小写字母,那么使用区间可以这样写:[a-z]
  3. 如果我们需要配大写字母,那么使用区间可以这样写:[A-Z]
  4. 对上述三种都需要匹配,那么可以这样写:[0-9a-zA-Z]

例如:

1638948216818.jpg

取反

有时我们希望排除某些字符来匹配其它字符,比如:我们现在希望匹配除了2和4其它所有的数字,按照正常字符组来写,我们会写成这样:[01356789]。如果是比较大的字符组的话,这样的写法会很麻烦,所有正则中提供了字符组取反的功能,在字符组开头加上^。上面的例子使用取反的话就可以这样写:[^24]:

如图:

1638948780250.jpg

匹配特殊字符-转义

在正则表达式中许多标点符号都具备特殊的含义:

  1. []: 表示字符组
  2. -: 表示区间 ......

当我们需要匹配字符中的[]-或其他特殊符号时,我们需要将特殊字符进行转义操作,即: \-\[\]

如图:

1638949494063.jpg

特殊字符

快捷字符

快捷字符:它的作用就是可以使用字符来代替某些常用的正则表达式。

字符含义
.匹配除换行符之外的任何单个字符,一个小数点代表一个任意字符,这个字符可以是数字、符号、中英文等
\w(小写w)匹配一个单字字符(字母、数字或者下划线),等价于 [A-Za-z0-9_]
\W(大写w)匹配一个非单字字符。等价于 [^A-Za-z0-9_]
\s(小写s)匹配一个空白字符,包括空格、制表符、换页符和换行符
\S(大写s)匹配一个非空白字符
\d匹配一个数字,等价于[0-9]。
\D匹配一个非数字,等价于[^0-9]。

锚字符

锚字符:它的作用就是可以确定某些需要匹配的字符的位置。

字符含义
^匹配字符串开头,或者当使用多行标志(m)时,匹配一行的开头。 这个会匹配到位置,而不是字符。
$匹配字符串结尾,或者当使用多行标志(m)时,匹配一行的结尾。 这个会匹配到位置,而不是字符
\b匹配一个词的边界。边界可以理解为两个“字”字符之间是否有其它非“字”字符,如:空格,符号等,如果存在空格,符号等非“字”字符,那么该字符便存在边界,正则便可以根据边界匹配到该字符
\B匹配一个非单词边界

重复

当我们期望一个字符连续匹配好几次,比如匹配手机号或者身份证的时候,使用之前的写法,我们匹配手机号只能这样写:/\d\d\d\d\d\d\d\d\d\d\d/需要写11个\d来表示11位的数字,这样做法十分麻烦,而且不够灵活,所以我们使用重复的字符语法来匹配出现多次的元素。

重复字符语法

字符含义
{n,m}匹配前一项字符至少n次,小于等于m次
{n,}匹配前一项字符n次或更多次
{n}匹配前一项字符n次
?匹配前一项字符0次或1次,也就是说前一项字符是可选的,等价于{0,1}
+匹配前一项字符1次或多次,等价于{1,}
*匹配前一项字符0次或多次,等价于{0,}

{n,m}字符语法-重复区间

有些时候,我们不确定匹配字符的重复次数,比如说:座机的区号,需要校验中国和俄罗斯的座机号。中国的是:86-10086,俄罗斯的是:7-10000。这时候就需要用到重复区间{m,n}

这时,我们需要匹配的电话号码的区号可能是1位也可能是2位,后面是5位数字,那么我们则需要这样写:\d{1,2}\-\d{5}

如图:

1638953725376.jpg

首先匹配1到2位的数字,然后需要匹配-,最后匹配5位数字。

{n,}字符语法-开闭区间

有些时候,我们不确定匹配字符的重复次数,比如说:座机的区号,需要校验多个国家的。他们区号和号码的位数都不确定,只有固定的格式xxx-xxxx。这时候就需要用到我们的开闭区间{n,}

例如:

1638954115232.jpg

匹配至少1位区号,然后匹配-符号,最后匹配至少5位号码。

{n}字符语法-重复

这个字符语法比较简单,就是将前面的字符匹配n次。

例如:

1638954451384.jpg

\d代表数字,后面加上重复字符语法{3},表示连续匹配3个数字。

? 字符语法-可选

?字符语法表示前面一个字符将匹配1次或0次。

例如:

1638954709456.jpg

l后面放置了可选字符语法,表示有l的时候则匹配,匹配的结果为hello,没有的时候则不匹配,匹配结果为helo

+字符语法与*字符语法

+字符语法:匹配前一项字符1次或多次,等价于{1,}

例如:

1638955056428.jpg

/a\d+/g表示在a字符串后面需要跟着至少1个数字的字符才能被匹配。

在这个例子中我们的字符串为a不符合正则表达式要求,所以没有被匹配到。

再看一个例子:

1638955249362.jpg

在上一个例子的基础上,我们在a后面添加了多个数字,符合正则表达式。

*字符语法:匹配前一项字符0次或多次,等价于{0,}

例如:

1638955498762.jpg

+字符语法不同,*字符语法表示在a后面至少跟着0个或更多个数字,就会被正则所匹配到。

分组

分组的字符语法:

字符含义
(x)匹配x项并且记住匹配项,使用$n表示被记住的匹配项
(?:x)匹配x项,但是不记住匹配项
`xy`匹配x或y
\n引用分组

捕获分组

捕获分组:就是匹配()中的字符,并且可以将匹配到的结果记住,通过$n来获取匹配结果。在捕获表达式中第一个捕获分组所得结果使用$1表示,第二个使用$2表示,以此类推第n个分组的结果使用$n表示。

例如:

// (\d{3}) 是第一个分组 对应 $1
// (\d{4}) 是第二个分组 对应 $2
const regexp = /(\d{3})-(\d{4})/g;
const str = '123-4567';
regexp.exec(str);

console.log(RegExp.$1); // 123
console.log(RegExp.$2); // 4567

非捕获分组

非捕获分组与捕获分组用法相同,不同的是匹配到的结果不会被记录,通过$n无法获取结果。

例如:

// (\d{3}) 是第一个分组 对应 $1
// (\d{4}) 是第二个分组 对应 $2
const regexp = /(?:\d{3})-(?:\d{4})/g;
const str = '123-1234';
regexp.exec(str);

console.log(RegExp.$1); // ''
console.log(RegExp.$2); // ''

引用分组

引用分组用于在一个字符中匹配的子字符规则多次出现。

例如:

<font>文字</font>

需要匹配html标签,将标签内容提取出来。

我们可以这样写:

1638959502910.jpg

可以看到,我们一共有两个分组:

  1. (\w+): html标签的分组,序号为1
  2. (.+): 标签内容的分组,序号为2

最后我们在闭合标签中使用了\1,去引用序号为1的分组,确保了html标签的一致。最后我们可以使用RegExp.$2获取出标签的内容。

或者条件

或者条件是使用|符号表示的与字符组类似,都是匹配多个选项。但是不同的是,字符组中的匹配项只能以单个字符的形式匹配,而或者条件的条件则可以是多个字符组成。

例如:

/[abc]/g // 字符组

/abc|asd|dfg/g // 或者条件

1638960082243.jpg

先行断言

正向先行断言

正向先行断言: (?=表达式),如:x(?=y),从左向右看,x后面必须跟着y才满足正向先行断言。

例如:

我喜欢你 我喜欢 我喜欢我 喜欢 喜欢你

需要取出喜欢两个字,需要喜欢后面有“你”,这个时候就要这么写:喜欢(?=你)

1638960578853.jpg

反向先行断言

反向先行断言: (?!表达式),如:x(?!y),从左向右看,x后面保证不跟着y才满足反向先行断言。

例如:

我喜欢你 我喜欢 我喜欢我 喜欢 喜欢你

需要取出喜欢两个字,需要喜欢后面没有“你”,这个时候就要这么写:喜欢(?!你)

反向先行.png

后行断言

正向后行断言

先行断言和后行断言只有一个区别,即先行断言从左往右看,后行断言从右往左看。

正向后行断言: (?<=表达式),如:(?<=y)x,从右向左看,x前面保证跟着y才满足正向后行断言。

例如:如果要取出喜欢两个字,要求喜欢的前面有我后面有你,这个时候就要这么写:(?<=我)喜欢(?=你)

正向后行断言.png

反向后行断言

反向后行断言: (?<!表达式),如:(?<!y)x,从右向左看,x前面保证不跟着y才满足反向后行断言。

例如:如果要取出喜欢两个字,要求喜欢的前面没有我后面没有你,这个时候就要这么写:(?<!我)喜欢(?!你)

反向后行断言.png

实战

到这里正则的基本知识都学习完成了,那我们来做点题目自我检测一下。

使用正则判断一个字符是否为小数

题目:

需要匹配:1.2 11.22 0.1 192.123456

不需要匹配:1 12 .12 12.12.12. 1.1.1.1 999

首先分析一下小数的特点:

  1. 以数字开头
  2. 只有一位小数点
  3. 以数字结尾

答案:/^\d+\.\d+$/g

我们来分析一下这个正则表达式:

  1. ^\d+:表示匹配至少一个或更多个以数字开头的字符。
  2. \.:使用字符转义,匹配字符小数点
  3. \d+$:表示匹配至少一个或更多个以数字结尾的字符

使用正则校验手机号码格式

题目:

校验手机号码格式是否正确?

规则:

  1. 必须是11位的数字;
  2. 第一位数字必须以1开头,第二位数字可以是[3,4,5,7,8]中的任意一个,后面9个数是[0-9]中的任意一个数字。

答案:/^1[3,4,5,7,8]\d{9}/g

我们来分析一下这个正则表达式:

  1. ^1:表示匹配开头位置为1的字符
  2. [3,4,5,7,8]:表示匹配第二个字符是3,4,5,7,8其中之一的字符
  3. \d{9}:表示匹配9个数字