正则表达式
正则是用来对字符串进行查找或者处理的
正则表达式是匹配模式(match pattern): 要么匹配字符, 要么匹配位置
正则表达式字符匹配攻略
主要内容:
在量词后面加上
?
表示惰性匹配(亦称作惰性量词)
- 两种模糊匹配
- 字符组
- 量词(+ 惰性匹配)
- 分支结构
- 案例分析
1. 两种模糊匹配
正则的强大在于其模糊匹配
正则的模糊匹配两种:横向模糊匹配 和 纵向模糊匹配
1.1 横向模糊匹配
横向模糊匹配: 一个正则可匹配的字符串长度不是固定的。
实现方式使用量词: 如:{m,n},表示某个或者某组字符的连续出现次数 至少 m 次, 至多 n 次
var regex = /ab{2,5}c/g;
var string = 'abc abbc abbbc abbbbc abbbbbc abbbbbbc';
console.log(string.match(regex));
// ["abbc", "abbbc", "abbbbc", "abbbbbc"]
其中, g 是正则的修饰符,表示全局匹配,即在目标字符串中按顺序找到满足匹配模式的所有有子串,强调的是 “所有” 而不是 “第一个”
注意下 g 和 贪婪匹配没有关系
1.2 纵向模糊匹配
纵向模糊匹配: 一个正则匹配的字符串,具体到某一位时候,可以是不确定的字符
实现方式: 如: [abc],表示该位字符可以是 字符 a , b ,c 中的任何一个。
var regex = /a[123]b/g;
var string = 'a0b a1b a2b a3b a4b';
console.log(string.match(regex)); //["a1b", "a2b", "a3b"]
2. 字符组
虽然叫字符组(字符类),但只是其中的一个字符。例如: [abc], 表示匹配一个字符,他可以是 字符’a’, ‘b’, ‘c’ 之一。
2.1 范围表示法
使用连字符 -
来省略和简写:
比如: [123456abcdefGHIJKLM]
可以简写为:[1-6a-fG-M]
因为 连字符有特殊用途,那么匹配 ‘a’, ‘-‘, ‘z’ 三者中的任意一个字符: [-az]或者[az-]或者[a\-z]
即要么放在开头要么放在结尾,或者转义,只要不让 引擎认为表示范围就好了
2.2 排除字符组
纵向模糊匹配的时候,有一种情形是: 某位字符上表示任何除了 a,b,c 字符外的任何字符
此时就是 排除字符组(反义字符组)的概念。 如: [^abc]
表示 一个除 ‘a’ , ‘b’ , ‘c’ 之外的任意一个字符。 字符组的第一位 ^
(脱字符) ,有取反 之意
当然,也有相应的范围表示法
2.3 常见的简写形式
\d 就是 [0-9] ,表示一位数字。对应英文 digit(数字)
\D 就是 [^0-9], 表示除数字外的任意字符
\w 就是 [0-9a-zA-Z_] 或者 [0-9A-z](注意 A-z ASCII 码) ,表示 数字,字母,下划线。 word (单词),单词字符
注意 \w 不包含 $ 符号
\W 就是 [^0-9a-zA-Z] , 表示非单词字符
\s 就是 [\t\v\n\r\f] , 表空白符(号),包括 空格, 水平制表符,垂直制表符,换行符,回车符,换页符。 对应英文: space character
\S 就是 [^\t\v\r\n\f], 表示非空白符号
. 就是 [^\n\r\u2028\u2029] 。 通配符,表示几乎任意字符,除了: 换行符,回车符,行分隔符和段分隔符
如果要匹配任意字符, 可以使用 [\d\D] 、[\w\W]、[\s\S] 和 [^] 中任何一个
3. 量词
量词也称作重复, 掌握 {m,n}
精准含义后,只需要记住一些简写形式。
3.1 简写形式
{m,}: 至少出现 m 次
{,n}: 至多出现 n 次
{m}: 出现 m 次
? : 等价于 {0,1} ,表示出现或者不出现
- : 等价于 {1,} 表示至少出现 1 次
*
: 等价于 {0,} 表示出现任意次, 有可能不出现
3.2 贪婪匹配 和 惰性匹配
看如下例子:
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 位连续数字
但是其是贪婪的,会尽可能多的匹配。能力范围内,越多越好
而惰性匹配,就是尽可能少的匹配:
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个就够的时候,就不再往下尝试了
通过在量词后面加个问号既可以实现惰性匹配,因此所有惰性匹配的情形如下:
一般只有量词才会涉及到贪婪和惰性
{m,n}?
{m,}?
??
+?
*?
惰性匹配的记忆方式: 量词后面加问号,问一句你知足了吗? 你很贪婪吗?
4. 多选分支
一个模式可以实现 横向和纵向的模糊匹配。而多选分支可以支持多个子模式任选其一。
具体形式: (p1| p2| p3)
,其中 p1 、p2 、p3 是子模式,用 | (管道符)分隔,表示其中任何之一。
var regex = /good|nice/g;
var string = "good idea , nice try";
console.log(string.match(regex));
// ["good", "nice"]
分支结构的匹配是 惰性匹配,即当前面的匹配上了,后面就不再尝试了
var regex = /good|goodbye/g;
var string = 'goodbye';
console.log(string.match(regex));
// => ["good"]
var regex = /goodbye|good/g;
var string = 'goodbye';
console.log(string.match(regex));
// => ["goodbye"]
5. 案例分析
匹配字符,无非就是 字符组、量词和分支机构的组合使用罢了
5.1 匹配16进制颜色值
建议在 [] 不要使用 \d 使用 0-9
注意在 正则表达式中不要随意加 空格,空格也是会匹配的
// 要求匹配: #ffbbad #Fc01Df #fff #ffE
// var regex = /#[0-9a-fA-F]{6} | #[0-9a-fA-F]{3}/g
var regex = /#[\da-fA-F]{6} | #[\da-fA-F]{3}/g;
var string = '#ffbbad #Fc01Df #fff #ffE';
console.log(string.match(regex));
// > ["#ffbbad", "#Fc01Df", "#fff", "#ffE"]
5.2 匹配时间
以24小时制为例。
要求匹配: 23:59 , 02:07
// 1. 共四位数, 第1位 可以是[0-2]
// 2. 当第一位 为2 时候, 第二位可以 [0-3],其他情况 第二位[0-9]
// 3. 第3 位 数字为 [0-5]
// 4. 第4位 为 [0-9]
var regex = /^([01][0-9]|[2][0-3]):[0-5][0-9]$/;
console.log(regex.test('23:59'));
console.log(regex.test('02:07'));
// > true
// > true
零可以省略情况:
// 扩大范围了
// var regex = /^([01]?[0-9]|[2][0-3]):[0-5]?[0-9]$/;
// var regex = /^(0?[0-9]|1[0-9]|[2][0-3]):((0?|[1-5])[0-9])$/;
// var regex = /^(0?[0-9]|1[0-9]|[2][0-3]):(0?[0-9]|[1-5][0-9])$/;
console.log(regex.test('23:59'));
console.log(regex.test('02:07'));
console.log(regex.test('2:7'));
// > true
// > true
// > true
5.3 匹配日期
比如: yyyy-mm-dd 格式为例
要求匹配:
分析:
- 年, 四位数字即可,可用 [0-9]{4}
- 月, 共12个月,分两种情况: 01、02…、09 和 10 、11、12, 可用 (0[1-9]|1[0-2] )
- 日,最大31 天,分为三种情况: 01、02、…、 09 和 10… 和 30、31,可用(0[1-9]|[12][0-9]|[3][01])
var regex = /^[0-9]{4}-0[1-9]|1[0-2]-0[1-9]|[12][0-9]|[3][01]$/
console.log(regex.test('2017-06-07'));
// true
5.4 window 操作系统文件路径
要求:
F:\study\javascript\regex\regular expression.pdf
F:\study\javascript\regex\
F:\study\javascript
F:\
分析:
- 整体的模式是:
盘符:\文件夹\文件夹\文件夹\
- 匹配
F:\
使用[a-zA-Z]:\\
,其中盘符不区分大小写,注意\
需要使用转义 - 文件名和文件夹:
[^\:*<>|"?\r\n/]
不能空名,至少一个字符,匹配文件夹:folder\
. 可用([^\:*<>|"?\r\n/]+\\)+
, 其中 括号提供子表达式 - 路径最后一部分可以是文件夹,没有 , 因此需要添加
([^\:*<>|"?\r\n/]+)?
// 这正则很棒,最后一位的匹配直接使用 ? 来区分 folder\ 类型的
var regex = /^[a-zA-Z]:\\([^\\:*<|"?\r\n/]+\\)*([^\\:*<>|"?\r\n/]+)?$/;
regex.test('F:\\study\\javascript')
regex.test('F:\\study\\javascript\regex\\regular expression.pdf');
regex.test('F:\\study\\javascript\\regex\\');
// true
5.5 匹配 id
要求: 提取 id="container"
首先想到:
var regex = /id=".*"/;
var string = '<div id="container" class="main" style="color: red;"></div>';
console.log(string.match(regex)[0]);
// id="container" class="main" style="color: red;"
因为 . 是通配符, 本身就可以匹配双引号,而 量词 * 本身又是贪婪的, 当遇到 container 后面双引号时候,不会停下来,会继续匹配,直到遇到最后一个双引号位置
优化如下:
var regex = /id="[^"]*"/;
var string = '<div id="container" class="main" style="color: red;"></div>';
console.log(string.match(regex)[0]);
// id="container"