正则表达式

在线正则匹配测试网站

开头

支持正则表达式的 String 对象的方法

方法 描述
search 检索与正则表达式相匹配的值。
match 返回的一个数组,第一个元素是整体匹配结果,然后是各个分组(括号里)匹配的内容,然后是匹配下标,最后是输入的文本。另外,正则表达式是否有修饰符 g,match返回的数组格式是不一样的。
replace 替换与正则表达式匹配的子串。
split 把字符串分割为字符串数组。

RegExp 对象方法

方法 描述
compile 编译正则表达式。
exec 检索字符串中指定的值。返回找到的值,并确定其位置。
test 检索字符串中指定的值。返回 true 或 false。

修饰符

修饰符 描述
i 执行对大小写不敏感的匹配。
g 执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。
m 执行多行匹配。

字符匹配

字符组

1
[abc]//标识匹配a、b、c中的一个

范围表示法(-)

1
2
[0-9a-zA-Z]//表示匹配任意以为包含在内的字符
[-az]//匹配 -、a、z中的一个,- 有特殊含义,如果需要匹配到 - 不能放在中间

排除字符组(^)

1
[^abc]//匹配非 a、b、c

常见简写形式

字符组 含义
\d 表示 [0-9]。表示是一位数字。记忆方式:其英文是 digit(数字)。
\D 表示 [^0-9]。表示除数字外的任意字符。
\w 表示 [0-9a-zA-Z_]。表示数字、大小写字母和下划线。记忆方式:w 是 word 的简写,也称单词字符。
\W 表示 [^0-9a-zA-Z_]。非单词字符。
\s 表示 [ \t\v\n\r\f]。表示空白符,包括空格、水平制表符、垂直制表符、换行符、回车符、换页符。记忆方式:s 是 space 的首字母,空白符的单词是 white space。
\S 表示 [^ \t\v\n\r\f]。 非空白符。
. 表示 [^\n\r\u2028\u2029]。通配符,表示几乎任意字符。换行符、回车符、行分隔符和段分隔符除外。记忆方式:想想省略号 … 中的每个点,都可以理解成占位符,表示任何类似的东西。

匹配任意字符

1
2
3
4
[\d\D]
[\w\W]
[\s\S]
[^]

量词({n,m})

量词 含义
{m,} 至少出现 m 次
{m} 等价于{m,m},出现 m 次
? {0,1} 0或1次
+ {1,} 1次以上
* {0,} 0次以上

贪婪匹配

尽可能多的匹配,给6个匹配5个,给4个就匹配4个

1
2
3
4
var regex = /\d{2,5}/g;
var string = "123 1234 12345 123456";
console.log( string.match(regex) );
// ["123", "1234", "12345", "12345"]

惰性匹配

量词后面加个问号(?),匹配到了就好了,不会匹配更多

1
2
3
4
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"]

小结

一、匹配16进制颜色值

1
2
3
4
var regex = /#([0-9a-zA-Z]{6}|[0-9a-zA-Z]{3})/g;
var string = "#ffbbad #Fc01DF #FFF #ffE";
console.log( string.match(regex) );
//["#ffbbad", "#Fc01DF", "#FFF", "#ffE"]

二、匹配时间

1
2
3
var regex = /^(2[0-3]|[0-1][0-9]):[0-5][0-9]$/;
regex.test("23:59");//true
regex.test("02:07");//true

三、window操作系统文件路径

1
2
3
4
5
var regex = /^[a-zA-Z]:\\([^\\:*<>|"?\r\n/]+\\)*([^\\:*<>|"?\r\n/]+)?$/;
console.log( regex.test("F:\\study\\javascript\\regex\\regular expression.pdf") );
console.log( regex.test("F:\\study\\javascript\\regex\\") );
console.log( regex.test("F:\\study\\javascript") );
console.log( regex.test("F:\\") );

四、匹配id

1
2
3
4
// var regex = /id=".*?"/;
var regex = /id="[^"]*?"/;
var string = '<div id="container" class="main"></div>';
console.log(string.match(regex)[0]);

位置匹配

脱字符(^)

匹配开头,多行匹配中配行开头 ,m表示允许多行匹配

1
2
3
4
5
6
7
8
9
var string = `my
name
is
qinhanwen`;
console.log(string.replace(/^/gm,"#"));
//#my
//#name
//#is
//#qinhanwen

美元符号($)

匹配结尾,多行匹配中匹配结尾

1
2
3
4
5
6
7
8
9
var string = `my
name
is
qinhanwen`;
console.log(string.replace(/$/gm,"#"));
//my#
//name#
//is#
//qinhanwen#

\b

\b 是单词边界,具体就是 \w\W 之间的位置,也包括 \w^ 之间的位置,和 \w$ 之间的位置。

1
2
3
4
5
6
7
var result = "[123],456]2".replace(/\b/g, '#');
console.log(result);//[#123#],#456#]#2#

var string = "#fffwff";
var reg = /#fff(?=f)ff/;
var reg1 = /#fff(?=f)ff/;
reg.test(string);//false

\B

非单词边界,也就是除了\b的,就都是\B

1
2
var result = "[123],456]2".replace(/\B/g, '#');
console.log(result);//#[1#2#3]#,4#5#6]2

(?=i)

某个位置后的字符匹配i

1
2
var string = "light";
string.replace(/(?=i)/,'#');//l#ight

(?!i)

某个位置后字符不匹配i

1
2
var string = "inline";
string.replace(/(?!i)/g,'#');//i#n#li#n#e#

小结

一、数字的千位分隔符

1
2
var result = "123456789".replace(/(?!^)(?=(\d{3})+$)/g, ',');
console.log(result);

其他形式千位分隔符

1
2
3
4
5
var result = "12346789 12346789".replace(/\B(?=(\d{3})+\b)/g, ',');
console.log(result);//12,346,789 12,346,789

var result = "12346789 12346789".replace(/((?!^)|[])(?=(\d{3})+\b)/g, ',');
console.log(result);//12,346,789 12,346,789

二、货币格式化

1
2
3
4
function format (num) {
return num.toFixed(2).replace(/\B(?=(\d{3})+\b)/g,",").replace(/^/,"$ ")
};
console.log( format(1888888888) );//$ 1,888,888,888.00

三、验证密码

密码长度 6-12 位,由数字、小写字符和大写字母组成, 必须同时包含数字、小写字母和大写字母

1
2
3
4
5
var reg = /(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])^[0-9a-zA-Z]{6,12}/;
var string = "21424245Aa2";
reg.test(string);//true
//(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])
//表示后面必须包含有一个大写,一个小写字符,和一个数值

(?=.*[0-9])表示某个位置之后由任意字符和一个数值组成

补充:

(?<=pattern):非获取匹配,反向肯定预查,与正向肯定预查类似,只是方向相反。例如,“(?<=95|98|NT|2000)Windows”能匹配“2000Windows”中的“Windows”,但不能匹配“3.1Windows”中的“Windows”。

(?<!patte_n): 非获取匹配,反向否定预查,与正向否定预查类似,只是方向相反。例如“(?<!95|98|NT|2000)Windows”能匹配“3.1Windows”中的“Windows”,但不能匹配“2000Windows”中的“Windows”。

括号的作用

分组功能

1
2
3
var regex = /(ab)+/g;
var string = "ababa abbb ababab";
console.log( string.match(regex) );//["abab", "ab", "ababab"]

分支结构

多选分支(|),它也是惰性匹配的,当前分支匹配上,后面就不尝试了

1
2
3
4
5
6
7
8
9
var regex = /(qin|qinhanwen)/g;
var string = "qinhanwen and qin";
console.log( string.match(regex) );
//["qin", "qin"]

var regex = /(qinhanwen | qin)/g;
var string = "qinhanwen and qin";
console.log( string.match(regex) );
//["qinhanwen ", " qin"]

分组引用

可以做数据提取,从而实现强大的替换操作

1
2
3
4
5
6
7
8
9
var regex = /(\d{4})-(\d{2})-(\d{2})/;
var string = "2017-06-12";
console.log(RegExp.$1); // "2017"
console.log(RegExp.$2); // "06"
console.log(RegExp.$3); // "12"
var result = string.replace(regex, "$2/$3/$1");// "06/12/2017"
var result1 = string.replace(regex, function () {
return RegExp.$2 + "/" + RegExp.$3 + "/" + RegExp.$1;
});// "06/12/2017"

反向引用

\1表示引用分组,对于不同的分组只要在\后加不同的数值就好了

1
2
3
4
5
6
7
8
9
var regex = /\d{4}(-|\/|\.)\d{2}\1\d{2}/;
var string1 = "2017-06-12";
var string2 = "2017/06/12";
var string3 = "2017.06.12";
var string4 = "2016-06/12";
console.log( regex.test(string1) ); // true
console.log( regex.test(string2) ); // true
console.log( regex.test(string3) ); // true
console.log( regex.test(string4) ); // false

括号嵌套

1
2
3
4
5
6
7
var regex = /^((\d)(\d(\d)))\1\2\3\4$/;
var string = "1231231233";
console.log( regex.test(string) ); // true
console.log( RegExp.$1 ); // 123
console.log( RegExp.$2 ); // 1
console.log( RegExp.$3 ); // 23
console.log( RegExp.$4 ); // 3

第一个分组:123

第二个分组:1

第三个分组:23

第四个分组:3

分组后面有量词

分组后面有量词的话,分组最终捕获到的数据是最后一次的匹配

1
2
3
4
5
var regex = /(\d)+ \1/;
console.log( regex.test("12345 1") );
// => false
console.log( regex.test("12345 5") );
// => true

非捕获括号

只需要括号最原始的功能,而不要引用它(不在API里引用,也不反向引用),可以使用:

1
(?:p)

小结

一、字符串trim方法

1
2
3
4
5
6
7
var string1 = "  asda s  ";
function trim(str){
return str.replace(/^\s*|\s*$/g,"");
// return str.replace(/^\s*(.*?)\s*$/g,"$1");
//这里的.*?使用惰性匹配,否则会匹配所有空格,除了最后一个
}
trim(string1);

二、单词首字母大写

1
2
3
4
5
6
7
8
9
function titleize(str){
return str.toLowerCase().replace(/(?=\b)\w/g,function(c){
return c.toUpperCase();
})
// return str.toLowerCase().replace(/(?:^|\s)\w/g,function(c){
// return c.toUpperCase();
// })
}
titleize('my name is qinhanwen')

三、首字母驼峰

1
2
3
4
5
6
camelize('-moz-transform')
function camelize(str){
return str.replace(/-(.)/g,function(match,c){
return c.toUpperCase();
})
}

四、中划线

1
2
3
4
5
6
dasherize('MozTransform')
function dasherize(str){
return str.replace(/[A-Z]/g,function(match){
return '-' + match.toLowerCase();
})
}

五、匹配成对标签

1
2
3
4
5
var regex = /<([^>]+)>.*<\/\1>/;
var string1 = "<title>regular expression</title>";
var string2 = "<title>regular expression</p>";
regex.test(string1);
regex.test(string2);

回溯

回溯法也称试探法,它的基本思想是:从问题的某一种状态(初始状态)出发,搜索从这种状态出发所能达到的所有“状态”,当一条路走到“尽头”的时候(不能再前进),再后退一步或若干步,从另一种可能“状态”出发,继续搜索,直到所有的“路径”(状态)都试探过。这种不断“前进”、不断“回溯”寻找解的方法,就称作“回溯法”。