正则基础匹配:
\d 是[0-9]
。表示是一位数字。
\D就是[^0-9]
。表示除数字外的任意字符。
\w就是[0-9a-zA-Z_]
。表示数字、大小写字母和下划线。记忆方式:w是word的简写,也称单词字符。
\W是[^0-9a-zA-Z_]
。非单词字符。
\s是[ \t\v\n\r\f]
。表示空白符,包括空格、水平制表符、垂直制表符、换行符、回车符、换页符。
\S是[^ \t\v\n\r\f]
。 非空白符。
. 就是[^\n\r\u2028\u2029]
。通配符,表示几乎任意字符。换行符、回车符、行分隔符和段分隔符除外。记忆方式:想想省略号...中的每个点,都可以理解成占位符,表示任何类似的东西。
量词
{m, n}
{m,} 表示至少出现m次。
{m} 等价于{m,m}
,表示出现m次。
? 等价于{0,1}
,表示出现或者不出现。记忆方式:问号的意思表示,有吗?
+ 等价于{1,}
,表示出现至少一次。记忆方式:加号是追加的意思,得先有一个,然后才考虑追加。
* 等价于{0,}
,表示出现任意次,有可能不出现。记忆方式:看看天上的星星,可能一颗没有,可能零散有几颗,可能数也数不过来。
{1, 5}
表示重复,1-5个。比如/\d{1,5}/ , 这个会匹配1到5个数字
?
这个是惰性匹配,相当于{0,1},表示有没有出现。/\d{1,5}?/。这个就是表示匹配数字,出现一个也可以。
正则匹配位置
位置
^
和$
^
(脱字符)匹配开头,在多行匹配中匹配行开头。
$
(美元符号)匹配结尾,在多行匹配中匹配行结尾。
看下面一个匹配开头或者结尾的例子:
var result = "hello".replace(/^|$/g, '#');
console.log(result); //"#hello#"
如果是多行的情况,那也比较有意思:
var result = "I\nlove\njavascript".replace(/^|$/gm, '#');
console.log(result);
/*
#I#
#love#
#javascript#
*/
\b
和\B
\b
是单词边界,具体就是\w
和\W
之间的位置,也包括\w
和^
之间的位置,也包括\w
和$
之间的位置。
看这个例子:
var result = "[JS] Lesson_01.mp4".replace(/\b/g, '#');
console.log(result);
// => "[#JS#] #Lesson_01#.#mp4#"
为什么会这样?我们知道,\w
是字符组[0-9a-zA-Z_]
的简写形式,即\w
是字母数字或者下划线的中任何一个字符。而\W
是排除字符组[^0-9a-zA-Z_]
的简写形式,即\W
是\w
以外的任何一个字符。
\B
就是\b
的反面的意思,非单词边界。例如在字符串中所有位置中,扣掉\b
,剩下的都是\B
的。
var result = "[JS] Lesson_01.mp4".replace(/\B/g, '#');
console.log(result);
// => "#[J#S]# L#e#s#s#o#n#_#0#1.m#p#4"
(?=p)
和(?!p)
(?=p)
,其中p
是一个子模式,即p
前面的位置。就是表示前面的位置。
比如(?=l)
,表示'l'字符前面的位置,例如:
var result = "hello".replace(/(?=l)/g, '#');
console.log(result);
// => "he#l#lo"
而(?!p)
就是(?=p)
的反面意思,比如:
var result = "hello".replace(/(?!l)/g, '#');
console.log(result);
// => "#h#ell#o#"
二者的学名分别是positive lookahead
和negative lookahead
。
中文翻译分别是正向先行断言和负向先行断言。
位置的特性
对于位置的理解,我们可以理解成空字符""。
比如"hello"字符串等价于如下的形式:
"hello" == "" + "h" + "" + "e" + "" + "l" + "" + "l" + "o" + "";
也等价于:
"hello" == "" + "" + "hello"
因此,把/^hello$/
写成/^^hello$$$/
,是没有任何问题的:
var result = /^^hello$$$/.test("hello");
console.log(result);
// => true
位置的一些案例
数字千分位分割
比如把"12345678",变成"12,345,678"。
这个可以使用(?=\d{3}$)
。
var result = "12345678".replace(/(?=\d{3}$)/g, ',')
console.log(result); // "12345,678"
但是这个只有一个逗号,咋搞?使用量词+
。
var result = "12345678".replace(/(?=(\d{3})+$)/g, ',')
console.log(result);
// => "12,345,678"
但是匹配12345?6789呢?你试试,会发现有问题,开头处也匹配了。
如何不匹配开头?匹配开头是^
,不匹配开头就是(?!^)
。
来看看:
var string1 = "12345678",
string2 = "123456789";
reg = /(?!^)(?=(\d{3})+$)/g;
var result = string1.replace(reg, ',')
console.log(result);
// => "12,345,678"
result = string2.replace(reg, ',');
console.log(result);
// => "123,456,789"
如果要把"12345678 123456789"替换成"12,345,678 123,456,789"。
此时我们需要修改正则,把里面的开头^
和结尾$
,替换成\b
:
var string = "12345678 123456789",
reg = /(?!\b)(?=(\d{3})+\b)/g;
var result = string.replace(reg, ',')
console.log(result);
// => "12,345,678 123,456,789"
其中(?!\b)
怎么理解呢?
要求当前是一个位置,但不是\b
前面的位置,其实(?!\b)
说的就是\B
。
因此最终正则变成了:/\B(?=(\d{3})+\b)/g
。
验证密码
密码长度6-12位,由数字、小写字符和大写字母组成,但必须至少包括2种字符。
不考虑“但必须至少包括2种字符”这一条件。我们可以容易写出:
var reg = /^[0-9A-Za-z]{6,12}$/;
假设,要求的必须包含数字,怎么办?此时我们可以使用(?=.*[0-9])
来做。
(?=.*[0-9])
表示任意字符前面包含数字(任意字符也表示空字符,开头处可以认为是一个空字符,比如上面的"hello" = "" + "" + "hello"
)。
所以这个正则可以那么写:
var reg = /(?=.*[0-9])^[0-9A-Za-z]{6,12}$/;
那么同时包含两种呢?
var reg = /(?=.*[0-9])(?=.*[a-z])^[0-9A-Za-z]{6,12}$/;
所以最终的是这样的结果:
var reg = /((?=.*[0-9])(?=.*[a-z])|(?=.*[0-9])(?=.*[A-Z])|(?=.*[a-z])(?=.*[A-Z]))^[0-9A-Za-z]{6,12}$/;
console.log( reg.test("1234567") ); // false 全是数字
console.log( reg.test("abcdef") ); // false 全是小写字母
console.log( reg.test("ABCDEFGH") ); // false 全是大写字母
console.log( reg.test("ab23C") ); // false 不足6位
console.log( reg.test("ABCDEF234") ); // true 大写字母和数字
console.log( reg.test("abcdEF234") ); // true 三者都有
换种解法
“至少包含两种字符”的意思就是说,不能全部都是数字,也不能全部都是小写字母,也不能全部都是大写字母。
那么要求“不能全部都是数字”,怎么做呢?(?!p)
出马!对应下面的正则:
var reg = /(?!^[0-9]{6,12}$)^[0-9A-Za-z]{6,12}$/;
三种都不能呢?
var reg = /(?!^[0-9]{6,12}$)(?!^[a-z]{6,12}$)(?!^[A-Z]{6,12}$)^[0-9A-Za-z]{6,12}$/;
console.log( reg.test("1234567") ); // false 全是数字
console.log( reg.test("abcdef") ); // false 全是小写字母
console.log( reg.test("ABCDEFGH") ); // false 全是大写字母
console.log( reg.test("ab23C") ); // false 不足6位
console.log( reg.test("ABCDEF234") ); // true 大写字母和数字
console.log( reg.test("abcdEF234") ); // true 三者都有
本文摘于:https://juejin.im/post/5965943ff265da6c30653879