正则表达式是用于匹配字符串中字符组合的模式,在 JavaScript
中,正则表达式也是对象。这些模式被用于 RegExp
的 exec
和 test
方法, 以及 String
的 match
、replace
、search
和 split
方法。
创建正则表达式
- 使用一个正则表达式字面量,其由包含在斜杠之间的模式组成,如下所示:
const regex = /ab+c/;
const regex = /^[a-zA-Z]+[0-9]*\W?_$/gi;
- 或者调用RegExp对象的构造函数,如下所示:
let regex = new RegExp("ab+c");
let regex = new RegExp(/^[a-zA-Z]+[0-9]*\W?_$/, "gi");
元字符
基本元字符
字符 | 含义 |
---|---|
. | 表示匹配除换行符以外的任意字符。例如 /.n/ 将会匹配 "nay, an apple is on the tree" 中的 'an' 和 'on' ,但是不会匹配 'nay' 。 |
[abc] | 表示匹配方括号中的任意字符,比如 /a[123]b/ 可以匹配如下三种字符串:"a1b"、"a2b"、"a3b" 。 |
[^abc] | 一个反向字符集。也就是说, 它匹配任何没有包含在方括号中的字符,你可以使用破折号(-) 来指定一个字符范围。例如,[^abc] 和 [^a-c] 是一样的。 |
x | y | 匹配‘x’或者‘y’。 优先级最低,例如,/green|red/ 匹配 “green apple” 中的 ‘green’ 和 “red apple” 中的 ‘red’ |
( ) | 1. 提升优先级. 2. 分组 |
x(?=y) | 匹配 'x' 仅仅当 'x' 后面跟着 'y'.这种叫做正向肯定查找。例如,/Jack(?=Sprat)/ 会匹配到 'Jack' 仅仅当它后面跟着 'Sprat' 。但是 ‘Sprat’ 不是匹配结果的一部分。 |
如果字符组里的字符特别多的话,可以使用范围表示法:比如[123456abcdefGHIJKLM]
,可以写成 [1-6a-fG-M]
。用连字符 -
来省略和简写。
限定元字符
字符 | 含义 |
---|---|
{m,n} | 表示连续出现最少m次,最多n次。 |
{m,} | 表示至少出现m次。 |
{m} | 等价于{m,m},表示出现m次。 |
? | 等价于{0,1} 表示要么0个或1个 |
+ | 等价于{1,},表示出现1次或多次 |
* | 表示0个或多个 |
简写元字符
字符 | 含义 |
---|---|
\d | 匹配一个数字。等于[0-9],数字的英文 digit |
\D | 匹配一个非数字字符,等价于[^0-9] |
\w | 匹配一个单词字符,表示数字、字母、下划线,等价于[0-1a-zA-Z_],w是word的简写 |
\W | 匹配一个非单词字符,等价于 [^0-9a-zA-Z_] |
\s | 表示空白字符,包括空格、制表符、换页符和换行符。等价于 [ \t\v\n\r\f] ,记忆方式:s是space character的首字母。例如, /\s\w*/ 匹配 "foo bar." 中的 ' bar' 。 |
\S | 表示非空白字符,例如 /\S\w*/ 匹配 "foo bar." 中的 'foo' 。 |
\b | 是单词边界,具体就是 \w 和 \W 之间的位置,也包括 \w 和 ^ 之间的位置,也包括 \w 和 $ 之间的位置。 |
\f | 匹配一个换页符 (U+000C)。 |
\n | 匹配一个换行符 (U+000A)。 |
\r | 匹配一个回车符 (U+000D)。 |
\t | 匹配一个水平制表符 (U+0009)。 |
\v | 匹配一个垂直制表符 (U+000B)。 |
一个文件名是 "[JS] Lesson_01.mp4"
中的 \b
,如下
var result = "[JS] Lesson_01.mp4".replace(/\b/g, '#');
console.log(result);
// => "[#JS#] #Lesson_01#.#mp4#"
位置元字符
字符 | 含义 |
---|---|
^ | 匹配输入的开始。例如,/^A/ 并不会匹配 "an A" 中的 'A',但是会匹配 "An E" 中的 'A'。 |
$ | 匹配输入的结束。例如,/t$/ 并不会匹配 "eater" 中的 't',但是会匹配 "eat" 中的 't'。 |
标志字符
字符 | 含义 |
---|---|
g | 表示全局搜索,global |
i | 表示不区分大小写,ignoreCase |
m | 多行搜索,multiline |
贪婪模式
贪婪模式是指在整个表达式匹配成功的前提下,尽可能多的匹配
var regex = /\d{2,5}/g;
var string = "123 1234 12345 123456";
console.log( string.match(regex) );
// => ["123", "1234", "12345", "12345"]
其中正则/\d{2,5}/,表示数字连续出现2到5次。会匹配2位、3位、4位、5位连续数字。
但是其是贪婪的,它会尽可能多的匹配。
var s = '1234567890';
var r = /(.+)(.+)(.+)/;
console.log( s.match(r) );
// ["1234567890", "12345678", "9", "0"]
第一个圆括号里匹配到的是 12345678
,第二个匹配到的是 9,第三个匹配到的是 0,从左到右,匹配个数的强度是由强到弱,但是只有两个级别,要么强要么弱,即第一个强,后面的几个一样弱。
有时贪婪不是一件好事,而惰性匹配,就是尽可能少的匹配:
var regex = /\d{2,5}?/g;
var string = "123 1234 12345 123456";
console.log( string.match(regex) );
// => ["12", "12", "34", "12", "34", "12", "34", "56"]
其中 /\d{2,5}?/
表示,虽然2到5次都行,当2个就够的时候,就不在往下尝试了。通过在量词后面加个问号就能实现惰性匹配。
正则对象的方法
test
接受一个字符串参数,如果正则表达式与指定的字符串匹配返回 true 否则返回 false
let str = 'hello world!';
let result = /^hello/.test(str);
console.log(result);
// true
exec
exec()
方法在一个指定字符串中执行一个搜索匹配。返回一个结果数组或 null
。
返回的数组将完全匹配成功的文本作为第一项,如果没有匹配到就返回 null
。数组还包含两个属性,index
表示匹配文本在字符串中的位置,input
表示被解析的原始字符串。
当正则表达式使用 "g"
标志时,可以多次执行 exec
方法来查找同一个字符串中的成功匹配。当你这样做时,查找将从正则表达式的 lastIndex
属性指定的位置开始。(test() 也会更新 lastIndex 属性)。
var reg = /ab*/g;
var str = 'abbcdefabh';
var myArray;
while ((myArray = reg.exec(str)) !== null) {
var msg = 'Found ' + myArray[0] + '. ';
msg += 'Next match starts at ' + reg.lastIndex;
console.log(msg);
}
// Found abb. Next match starts at 3
// Found ab. Next match starts at 9
如果正则表达式中有分组(有圆括号),分组都是从 1 开始的编号,第一项匹配到的结果就在数组的第 1 项,第 n 项匹配到的结果就在数组的第 n 项。
var s = '1234567890';
var r = /(.+)(.+)(.+)/;
console.log(r.exec(s);
// ["1234567890", "12345678", "9", "0", index: 0, input: "1234567890", groups: undefined]
String 对象的正则方法
replace
语法如下:
str.replace(regexp|substr, newSubStr|function)
接受两个参数,第一个参数是要替换的文本,可以是正则或字符串,如果是字符串则作为检索的直接量文本,第二个是字符串或函数,如果是字符串,该字符串中可以内插一些特殊的变量名。如果是函数,该函数的返回值将替换掉第一个参数匹配到的结果。
var str = 'Twas the night before Xmas...';
var newstr = str.replace(/xmas/i, 'Christmas');
console.log(newstr); // Twas the night before Christmas...
如果第二个参数是字符串,可以插入如下特殊变量名:
变量名 | 代表的值 |
---|---|
? | 插入一个 "$"。 |
$& | 插入匹配的子串。 |
$` | 插入当前匹配的子串左边的内容。 |
$' | 插入当前匹配的子串右边的内容。 |
$n | 假如第一个参数是 RegExp对象,并且 n 是个小于100的非负整数,那么插入第 n 个括号匹配的字符串。提示:索引是从1开始 |
// 交换字符串中的两个单词
var re = /(\w+)\s(\w+)/;
var str = "John Smith";
var newstr = str.replace(re, "$2, $1");
console.log(newstr); // Smith, John
var s = "2017-1-7";
var r = /(\d+)\-(\d+)\-(\d+)/; // 分成三组
var a = s.replace(r,"$1年$2月$3日");
var b = s.replace(r,"$1/$2/$3");
console.log(a); // 2017年1月7日
console.log(b); // 2017/1/7
替换的时候,第二个参数可以是函数,函数的参数为匹配到的数组的散列值(相当于用exec方法匹配到的数组)
var s = "2017-1-7";
var r = /(\d+)\-(\d+)\-(\d+)/; //分成三组
var a = s.replace(r, function (a,b,c,d) {
return b + "年" + c + "月" + d + "日";
//a是匹配到的结果
//b是第一组匹配到的结果
//c是第二组匹配到的结果
//d是第三组匹配到的结果
});
console.log(a); //2017年1月7日
电话号码加密:
var list = [
'12345678901',
'12345678912',
'12345678923',
'12345678934',
'12345678945',
'12345678956'
];
var r = /(\d{4})(\d{4})(\d{3})/;
var newArr = list.map(function (v) {
return v.replace(r, function (a,b,c,d) {
return b + "********".slice(0,c.length) + d;
});
});
console.log(newArr);
match
参数为一个 正则表达式 对象,如果传入一个非正则表达式对象,则会隐式地使用 new RegExp(obj)
将其转换为一个 RegExp
。
- 如果使用
g
标志,则将返回与完整正则表达式匹配的所有结果(Array
),但不会返回捕获组,或者未匹配 null。 - 如果未使用
g
标志,则仅返回第一个完整匹配及其相关的捕获组(Array
)。 在这种情况下,返回的项目将具有如下所述的其他属性,或者未匹配 null。- groups: 一个捕获组数组 或 undefined(如果没有定义命名捕获组)。
- index: 匹配的结果的开始位置
- input: 搜索的字符串.
如果正则表达式不包含 g 标志,str.match() 将返回与 RegExp.exec(). 相同的结果,如下面例子所示。
var str = 'For more information, see Chapter 3.4.5.1';
var re = /see (chapter \d+(\.\d)*)/i;
var found = str.match(re);
console.log(found);
// logs [ 'see Chapter 3.4.5.1',
// 'Chapter 3.4.5.1',
// '.1',
// index: 22,
// input: 'For more information, see Chapter 3.4.5.1' ]
// 'see Chapter 3.4.5.1' 是整个匹配。
// 'Chapter 3.4.5.1' 被'(chapter \d+(\.\d)*)'捕获。
// '.1' 是被'(\.\d)'捕获的最后一个值。
// 'index' 属性(22) 是整个匹配从零开始的索引。
// 'input' 属性是被解析的原始字符串。
如果 表达式中包含 g 标:
var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
var regexp = /[A-E]/gi;
var matches_array = str.match(regexp);
console.log(matches_array);
// ['A', 'B', 'C', 'D', 'E', 'a', 'b', 'c', 'd', 'e']
split
语法为 str.split([separator[, limit]])
第一个参数可以为字符串或者正则表达式对象,如下所示:
var myString = "Hello 1 word. Sentence number 2.";
var split1 = myString.split(/\d/);
console.log(split1); // ["Hello ", " word. Sentence number ", "."]
// 如果包含括号,则其匹配结果将会包含在返回的数组中。
var split2 = myString.split(/(\d)/);
console.log(split2); // [ "Hello ", "1", " word. Sentence number ", "2", "." ]