正则表达式 RegExp

目录

1. 介绍

正则表达式,又称正规表示式、正规表示法、正规表达式、规则表达式、常规表示法(英语:Regular Expression,在代码中常简写为regex、regexp或RE),是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些匹配某个模式的文本。

正则表达式不是js、java或者其他某一种计算机语言特有,而是不同语言中都有,例如Python、php、Ruby、C++……,是用来处理文本的一种特定语法规则。

2. 语法

2.1 元字符

元字符 描述
. 句号匹配任意单个字符,除了换行符
[ ] 字符种类. 匹配方括号内的任意字符
[^ ] 否定的字符种类. 匹配除了方括号内的任意字符
* 匹配>=0个重复在*号前的字符
+ 匹配>=1个+号前的字符
{n, m} n是min最小数量,m为max为最大数量,匹配这个区间个数的中括号前的字符
? 标记?之前的字符为可选; 等价于 {0,1}。
(xyz) 字符集,匹配与xyz完全相等的字符
模式 /(foo) (bar) \1 \2/ 中的 ‘(foo)’ 和 ‘(bar)’ 匹配并记住字符串 “foo bar foo bar” 中前两个单词。模式中的 \1 和 \2 匹配字符串的后两个单词。注意 \1、\2、\n 是用在正则表达式的匹配环节。在正则表达式的替换环节,则要使用像 $1、$2、$n 这样的语法 ,例如,’bar foo’.replace( /(…) (…)/, ‘$2 $1’ )。
3. 1 replace 多参数匹配
\ 转义字符,用于匹配一些保留的字符 [ ] ( ) { } . * + ? ^ $ \ |
^ 匹配输入的开始。如果多行标志被设置为true,那么也匹配换行符后紧跟的位置。
例如,/^A/ 并不会匹配 “an A” 中的 ‘A’,但是会匹配 “An E” 中的 ‘A’。
当 ‘^’ 作为第一个字符出现在一个字符集合模式时,它将会有不同的含义
$ 匹配输入的结束。如果多行标示被设置为true,那么也匹配换行符前的位置。
例如,/t$/ 并不会匹配 “eater” 中的 ‘t’,但是会匹配 “eat” 中的 ‘t’。

2.2 字符集

简写 描述
\w 匹配一个单字字符:数字、字幕或下滑线; 等价月[A-Za-z0-9_]
\W 匹配非单字字符,等价于[^A-Za-z0-9_]
\d 匹配一个数字,等价于[0-9]
\D 匹配一个非数字字符,等价于[^0-9]
\s 匹配一个空白字符, 包括空格、制表符、换页符和换行符
\S 匹配一个非空白字符。
\f 匹配一个换页符
\n 匹配一个换行符
\r 匹配一个回车符
\t 匹配一个水平制表符
\v 匹配一个垂直制表符
\p 匹配 CR/LF (等同于 \r\n),用来匹配 DOS 行终止符

2.3 修饰符

正则表达式的修饰符,修饰符放在’/‘符号之外,JavaScript支持三个修饰符

字符 描述
i 执行不区分大小写的匹配
g 执行一个全局的匹配;查找所有的匹配,而不是找到第一个之后就停止
m 多行匹配;
例如:/java$/im 可以匹配’java’, 也可以匹配“java\nis fun”

3. 高级语法

3.1 replace 多参数匹配

1
2
3
4
5
6
7
function replacer(match, p1, p2, p3, offset, string) {
// p1 is nondigits, p2 digits, and p3 non-alphanumerics
return [p1, p2, p3].join(' - ');
}
var newString = 'abc12345#$*%'.replace(/([^\d]*)(\d*)([^\w]*)/, replacer);
// 输出结果:
// abc - 12345 - #$*%

零宽断言

用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言

(?=exp) 也叫零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp。

例如:/[Jj]ava([Ss]cript)?(?=\:)/ 可以匹配”JavaScript: The Definitive Guide” 中的 “JavaScript”;但是不能匹配”Java in a Nutshell” 中的 “Java”,因为没有匹配断言中的“:”

负向零宽断言

零宽断言的相反,指定位置不包含满足条件的;(?! exp)

1
2
3
4
5
var reg = /Java(?!Script)([A-Z\w*]+)/g; // 匹配Java后面没跟有"Script"
var str = "a JavaScript Javaas";
str.match(reg); // 返回 ["Javaas"]

贪婪与懒惰

4. 使用

4.1 正则在js中的使用

正则在JavaScript里面的使用,有两种形式:

+. 一种是RegExp() 的exec()test()
+. 一种是String的match、split、replace、search

RegExp

正则表达式也是JavaScript对象。RegExp() 构造函数带有两个参数,第一个参数是正则表达式的直接量,也就是两条斜线中间的文本,但是转义字符需要单斜线改为双斜线:'\' --> '\\';第二个参数是可选的,也就是正则表达式的修饰符,也就是上面提到的g、i、m

1
2
3
4
5
例子:
let regexp1 = new RegExp('ab+c');
let regexp2 = new RegExp('\\d{5}', 'g');
let regexp3 = new RegExp(/^[a-zA-Z]+[0-9]*\W+_$/, "gi"); // 匹配'abc123*_'
let regexp4 = new RegExp("^[a-zA-Z]+[0-9]*\W+_$", "gi"); // 这个正则其实和上面的例子其实是不相等的,需要将\W+ 改为 \\W+

test() 用法: 参数是字符串,结果返回boolean,如果符合正则表达式则返回true

1
2
3
let regexp1 = new RegExp('ab+c');
regexp1.test('abbc'); // false
regexp1.test('abbc'); // true

exec() 用法:

regexObj.exec(str) 匹配失败返回null、匹配成功返回一个数组

这是个比较稍微难理解的使用方法,但是使用确实很频繁,因为实用。
首先,匹配失败返回null,成功是返回的是一个数组类型
其次,既然是数组,那肯定可能就有多个结果;

数组的第一位,是与正则表达式相匹配的字符串;

数组的第二位和之后的,是正则表达式”( )”中相匹配的;

1
2
3
4
5
6
var re = /quick\s(brown).+?(jumps)/ig;
var result = re.exec('The Quick Brown Fox Jumps Over The Lazy Dog');
console.log(result)
// console: ["Quick Brown Fox Jumps", "Brown", "Jumps"]
// 数组第一位是正则匹配,第二位 和第三位 对应正则里的两个”()“

很常见到exec会在while循环里使用;当正则表达式使用 “g” 标志时,可以多次执行 exec 方法来查找同一个字符串中的成功匹配。当你这样做时,查找将从正则表达式的 lastIndex 属性指定的位置开始。

1
2
3
4
5
6
7
8
9
10
11
12
var myRe = /ab*/g;
var str = 'abbcdefabh';
var myArray;
while ((myArray = myRe.exec(str)) !== null) {
var msg = '匹配到的数据是 -> ' + myArray[0] + '. ';
msg += '| 下一次匹配位置 -> ' + myRe.lastIndex;
console.log(msg);
}
// console 打印:
// 匹配到的数据是 -> abb. | 下一次匹配位置 -> 3
// 匹配到的数据是 -> ab. | 下一次匹配位置 -> 9

String

search() 参数是正则表达式,返回一个素质,找不到返回-1,找到返回匹配的起始位置; 如果参数不是正则表达式,会RegExp构造函数转换成正则表达式。不支持全局搜索,忽略正则表达式上的修饰符g;

1
2
3
"JavaScript".search('/vaS/i');
// 结果 return 2;

replace(), 两个参数,第一个正则表达式,第二个是需要替换的字符。如果第一个参数是字符串不是正则表达式,replace不会将字符串转化为RegExp(),而是直接搜索该字符串,如果不是g 全局匹配,replace只会替换第一个匹配的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
基本用法:
"javascript is the best language".replace(/javascript/gi, "JavaScript");
高级用法:
var a = "\"bich\" go die"
// $1 代表子表达式(exp)匹配的字符
// 将bich保存在$1中 不被修改
var b = a.replace(/"([^"]*)"/, '“$1”');
console.log(b)
// console结果:中文半角引号替换英文引号,引号内容不变
// “bich” go die

split()

1
2
3
var text = "1, 2, 3, 4"
var result = text.split(/\s*,\s*/); // 去除空格
console.log(result) // 返回["1","2","3","4"]

match() 参数为正则表达,如果是字符串也会转成RegExp()对象,返回是数组类型,包含所有匹配的结果,如果没有设置全局搜索的修饰符g,只会返回只包含第一个匹配的数组;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//一个具有字表达的match例子
var url = /(\w+):\/\/([\w.]+)\/(\S*)/;
var URLText = 'Visit my blog http://lixingdecai.com/home'
var result = URLText.match(url)
if(result != null) {
console.log(result[0]); // 第一个位置存储完整的匹配结果
console.log(result[1]); // 存放第一个子表达式匹配的结果
console.log(result[2]); // 存放第二个子表达式 也就是(exp)匹配的,后面以此类推
console.log(result[3]);
}
// console结果
// http://lixingdecai.com/home
// http
// lixingdecai.com
// home

4.2 正则表达式的应用场景

  1. web 表单校验

我们前端工程师非常熟悉的表单校验,要校验是否输入纯数字、合法身份证、合法手机号等等、

  1. CSS 选择器引擎

几乎所有的 CSS 选择器引擎会使用正则表达式。jQuery 所使用的选择器引擎 Sizzle.js 使用了大量的正则表达式以匹配各式各样的 CSS 选择器。

  1. 爬虫

你要从一网页中截取有效信息,大部分爬虫都是使用正则表达式去匹配提取需要的信息

  1. 编译器

在高级点使用,如编译器,大部分编译型编程语言设计的程序在执行之前要经历三个步骤:

+. 分词/词法分析
+. 语法分析,生成抽象语法树(AST)
+. 翻译为字节码/机器码

JS 正在表达式 MDN

learn-regex