JS正则表达式教程:https://juejin.im/post/5965943ff265da6c30653879
第一章 正则表达式字符匹配攻略
正则表达式是匹配模式,要么匹配字符,要么匹配位置。请记住这句话。
两种模糊匹配 1.1 横向模糊匹配 /ab{2,5}c/ 1.2纵向模糊匹配 /a[123]b/
2.1 匹配“a”、“-”、“z”这三者中任意一个字符,不能写成[a-z],
写成:[-az]
或[az-]
或[a\-z]
。
2.2 排除字符组
[^abc]
,表示是一个除"a"、"b"、"c"之外的任意一个字符。
2.3 常见的简写形式
\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 character的首字母。
\S
是[^ \t\v\n\r\f]
。 非空白符。
.
就是[^\n\r\u2028\u2029]
。通配符,表示几乎任意字符。换行符、回车符、行分隔符和段分隔符除外。记忆方式:想想省略号...中的每个点,都可以理解成占位符,表示任何类似的东西。
如果要匹配任意字符怎么办?可以使用[\d\D]
、[\w\W]
、[\s\S]
和[^]
中任何的一个。
3.2贪婪匹配和惰性匹配
{m,n}?
{m,}?
??
+?
*?
var regex = /id="[^"]*"/ var string = '<div id="container" class="main"></div>'; console.log(string.match(regex)[0]);
第二章 正则表达式位置匹配攻略
在ES5中,共有6个锚字符:
^
$
\b
\B
(?=p)
(?!p)
\b
是单词边界 \B
就是\b
的反面的意思,非单词边界。
2.3 (?=p)和(?!p)
(?=p)
,其中p
是一个子模式,即p
前面的位置
var result = "hello".replace(/(?=l)/g, '#'); console.log(result); // => "he#l#lo"
"123456789".replace(/(?!^)(?=(\d{3})+$)/g,",")
如果要把"12345678 123456789"替换成"12,345,678 123,456,789"。
此时我们需要修改正则,把里面的开头^
和结尾$
,替换成\b
4.3 验证密码问题
密码长度6-12位,由数字、小写字符和大写字母组成,但必须至少包括2种字符。
不考虑“但必须至少包括2种字符”这一条件 /^[0-9A-Za-z]{6,12}$/
要求的必须包含数字 var reg = /(?=.*[0-9])^[0-9A-Za-z]{6,12}$/;
比如同时包含数字和小写字母,可以用(?=.*[0-9])(?=.*[a-z])
来做。
因此正则变成:
var reg = /(?=.*[0-9])(?=.*[a-z])^[0-9A-Za-z]{6,12}$/;复制代码
4.3.4 解答
我们可以把原题变成下列几种情况之一:
- 同时包含数字和小写字母
- 同时包含数字和大写字母
- 同时包含小写字母和大写字母
- 同时包含数字、小写字母和大写字母
以上的4种情况是或的关系(实际上,可以不用第4条)。
最终答案是:
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 三者都有复制代码
4.3.6 另外一种解法
“至少包含两种字符”的意思就是说,不能全部都是数字,也不能全部都是小写字母,也不能全部都是大写字母。
那么要求“不能全部都是数字”,怎么做呢?(?!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 三者都有复制代码
第三章 正则表达式括号的作用
/^I love (JavaScript|Regular Expression)$/
如果去掉正则中的括号,即/^I love JavaScript|Regular Expression$/
,匹配字符串是"I love JavaScript"和"Regular Expression",当然这不是我们想要的。
3. 反向引用
/\d{4}(-|\/|\.)\d{2}\1\d{2}/;
3.2 \10表示什么呢?
另外一个疑问可能是,即\10
是表示第10个分组,还是\1
和0
呢?
答案是前者,虽然一个正则里出现\10
比较罕见。测试如下:
var regex = /(1)(2)(3)(4)(5)(6)(7)(8)(9)(#) \10+/;var string = "123456789# ######"console.log( regex.test(string) );// => true复制代码
第4章 正则表达式回溯法原理
3. 常见的回溯形式
3.1 贪婪量词
比如b{1,3}
,因为其是贪婪的
如果当多个贪婪量词挨着存在,并相互有冲突时,此时会是怎样?
答案是,先下手为强!因为深度优先搜索。测试如下:
var string = "12345";var regex = /(\d{1,3})(\d{1,3})/;console.log( string.match(regex) );// => ["12345", "123", "45", index: 0, input: "12345"]复制代码复制代码
其中,前面的\d{1,3}
匹配的是"123",后面的\d{1,3}
匹配的是"45"。
虽然惰性量词不贪,但也会有回溯的现象。
3.3 分支结构
- 贪婪量词“试”的策略是:买衣服砍价。价钱太高了,便宜点,不行,再便宜点。
- 惰性量词“试”的策略是:卖东西加价。给少了,再多给点行不,还有点少啊,再给点。
- 分支结构“试”的策略是:货比三家。这家不行,换一家吧,还不行,再换。
第5章 正则表达式的拆分
JS正则表达式中,都有哪些结构呢?
字符字面量、字符组、量词、锚字符、分组、选择分支、反向引用。
字面量,匹配一个具体字符,包括不用转义的和需要转义的。比如a匹配字符"a",又比如\n
匹配换行符,又比如\.
匹配小数点。
字符组,匹配一个字符,可以是多种可能之一,比如[0-9]
,表示匹配一个数字。也有\d
的简写形式。另外还有反义字符组,表示可以是除了特定字符之外任何一个字符,比如[^0-9]
,表示一个非数字字符,也有\D
的简写形式。
量词,表示一个字符连续出现,比如a{1,3}
表示“a”字符连续出现3次。另外还有常见的简写形式,比如a+
表示“a”字符连续出现至少一次。
锚点,匹配一个位置,而不是字符。比如^匹配字符串的开头,又比如\b
匹配单词边界,又比如(?=\d)
表示数字前面的位置。
分组,用括号表示一个整体,比如(ab)+
,表示"ab"两个字符连续出现多次,也可以使用非捕获分组(?:ab)+
。
分支,多个子表达式多选一,比如abc|bcd
,表达式匹配"abc"或者"bcd"字符子串。
反向引用,比如\2
,表示引用第2个分组。