我们应该知道,正则表达式是匹配模式,要么匹配字符,要么匹配位置。
一、两种模糊匹配
如果正则只有精确匹配是没多大意义的,比如/hello/,也只能匹配字符串中的"hello"这个子串。
1、横向模糊匹配
横向模糊指的是,一个正则可匹配的字符串的长度不是固定的,可以是多种情况的。
例如使用两次{m, n}, 最少匹配m次,最多匹配n次。
比如/ab{2,5}c/表示匹配这样一个字符串:第一个字符是“a”,接下来是2到5个字符“b”,最后是字符“c”。例子如下:
var reg = /ab{2,5}c/g;
var str = "abc abbc abbbc abbbbc abbbbbc abbbbbbc";
console.log(str.match(reg))
// => ["abbc", "abbbc", "abbbbc", "abbbbbc"]
注意:学过正则的朋友都知道正则表达式后面的g是全局匹配的标识符,就是找到字符串中所有符合正则表达式的匹配模式,g是单词global的首字母。
2、纵向模糊匹配
纵向模糊指的是,一个正则匹配的字符串,具体到某一位字符时,它可以不是某个确定的字符,可以有多种可能。
比如/a[123]b/可以匹配如下三种字符串:"a1b"、"a2b"、"a3b"。例子如下:
var reg = /a[123]c/g;
var str = "a0c a1c a2c a3c a4c";
console.log(str.match(reg))
// => ["a1c", "a2c", "a3c"]
二、字符组
虽然说是字符组,但是表示其中一个字符,例如[abc]表示”a“, ”b“, ”c“其中之一。
1、范围表示法
如果字符比较多的情况下就可以用范围表示法,例如要匹配a-z这26个英文字母其中任意字符,正则就可以用/[a-z]来表示。需要注意的是如果还要匹配 "-" 这个字符串,需要/[-a-z]/,例子如下:
var reg = /[a-z]/g;
var str = "avsf12-df";
console.log(str.match(reg))
// => ["a", "v", "s", "f", "d", "f"]
var reg = /[-a-z]/g;
var str = "avsf12-df";
console.log(str.match(reg))
// => ["a", "v", "s", "f", "-", "d", "f"]
2、排除字符组
纵向模糊匹配,还有一种情形就是,某位字符可以是任何东西,但不能是"a", "b", "c", "d"中的字符,这是用正则/[abcd]/表示,(脱字符),表示取反的意思。例子如下:
var reg = /[^abcd]/g;
var str = "safgecdb";
console.log(str.match(reg))
// => ["s", "f", "g", "e"]
3、常见的简写形式
\d
就是[0-9]。表示以为数字。
\D
就是[^0-9]。表示除数字外的任意字符。
\w
就是[0-9a-zA-Z_]。表示数字、大小写字母和下划线。
\W
是[^0-9a-zA-Z_]。非单词字符。
\s
是[ \t\v\n\r\f]。表示空白符,包括空格、水平制表符、垂直制表符、换行符、回车符、换页符。
\S
是[^ \t\v\n\r\f]。 非空白符。
.
就是[^\n\r\u2028\u2029]。通配符,表示几乎任意字符。换行符、回车符、行分隔符和段分隔符除外。
三、量词
1、简写形式
{m,}
至少出现m次。
{m}
等价于{m, m}, 出现m次。
?
等价于{0,1}, 出现或不出现。
+
等价于{1,},表示出现至少一次。
*
等价于{0,},可以不出现,也可以出现很多次,任意次。
2、贪婪匹配和惰性匹配
例子如下:
var reg = /\d{2,5}/g;
var str = "123 1234 12345 123456";
console.log(str.match(reg))
// => ["123", "1234", "12345", "12345"]
上面例子表示匹配2到5个数字, 可以是2位,3位,4位,5位数字,只要在这个范围之内,尽可能多的匹配,但有的时候并不需要这种匹配方式,我们可以在量词后面加" ?"来解除这种模式。
例子如下:
var reg = /\d{2,5}?/g;
var str = "123 1234 12345 123456";
console.log(str.match(reg))
// => ["12", "12", "34", "12", "34", "12", "34", "56"]
四、多选分支
一个模式可以实现横向和纵向模糊匹配。而多选分支可以支持多个子模式任选其一。
例如(a | b | c)这种方式匹配的是"a" 或 "b" 或 "c"的其中一种子模式。| 是管道符的意思。
例子如下:
var reg = /good|nice/g;
var str = "good idea, nice try";
console.log(str.match(reg))
// => ["good", "nice"]
需要注意的是如果我们用正则/good|goodbye/去匹配"goodbye",结果如下:
var reg = /good|goodbye/g;
var str = "goodbye";
console.log(str.match(reg))
// => ["good"]
需要爆正则改成/goodbye|good/这种方式,如下:
var reg = /goodbye|good/g;
var str = "goodbye";
console.log(str.match(reg))
// => ["goodbye"]
可以看出管道符匹配这种模式也是惰性的,如果前面符合条件,就不再匹配后面的。
五、案例分析
1、匹配16进制颜色值
表示一个16进制字符,可以用字符组[0-9a-fA-F]。
其中字符可以出现3或6次,需要是用量词和分支结构。
例子如下:
var reg = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g;
var str = "#ffbbad #Fc01DF #FFF #ffE";
console.log( str.match(reg) );
// => ["#ffbbad", "#Fc01DF", "#FFF", "#ffE"]
2、匹配id
要求从"<div id="container" class="main"></div>"取出"id="container"
开始我们可能想到
var reg = /id=".*"/
var str = '<div id="container" class="main"></div>';
console.log(str.match(reg)[0]);
// => id="container" class="main"
上面的例子我们没有解除正则的贪婪模式,解除掉贪婪模式的正则如下:
var reg = /id=".*?"/
var str = '<div id="container" class="main"></div>';
console.log(str.match(reg)[0]);
// => id="container"
我们得到了我们想要的,不过效率比较低,正则中有“回溯”这个概念,利用它的原理我们可以优化上面的正则如下:
var reg = /id="[^"]*"/
var str = '<div id="container" class="main"></div>';
console.log(str.match(reg)[0]);
// => id="container"