流光容易把人抛
人间朝暮
慢慢散步
-------写下便是永恒
文章目录
一、正则表达式匹配攻略
正则是匹配模式:
要么匹配字符
要么匹配位置
1.1 两种模式匹配
为什么是模糊匹配,因为如果正则是精准匹配,那么将没有任何意义
/hello/.test(‘hello’);// 只能匹配 hello 字符串,还有什么意义
模糊匹配分为两个方向:横向模糊和纵向模糊
1.1.1横向模糊匹配
就是一个正则可匹配的字符串长度不是固定的,可以是多种情况的。实现方式是使用量词。
如:{m,n} 表示连续出现最少 m 次 最多 n 次
const regex = /ab{2,5}c/g;
const string = 'abc abbc abbbc abbbbc abbbbbc abbbbbbc';
string.match(regex);// ... 这里打印什么
案例中的 g 是一个正则的修饰符。表示全局匹配,即在目标字符串中按顺序找到满足匹配模式的所有字符串,强调的是 ‘所有’,而不是第一个。g 是单词 global 的缩写。
1.1.2纵向模糊匹配
指一个正则匹配的字符串,具体到某一位字符时,它可以不是某个确定的字符,可以有多种可能。
[123] 表示该字符可以是 1 2 3 中的任意一个
const regex = /a[123]b/g;
const str = 'a0b a1b a2b a3b a12b a23b';
str.match(regex)//
1.2字符组
虽然叫做字符组,但是只匹配其中的一个。
比如 [123] 只匹配 1 2 3 其中之一
1.2.1范围表示法
如果字符组里面字符特别多可以使用范围表示法。
[12345abcdeABCDE] 可以写成 [1-5a-eA-E] 使用连接符来省略和简写
连接符 - 有特殊的作用。
那么思考一下要匹配 ‘a’ ‘-’ ‘z’ 怎么处理?
[a-z] 肯定是不对的,这个表达式表示小写字符中的任意一个。
// [-az]或[az-]或[a-z] (可以放开头、结尾或转译,不让引擎认为是范围表示法就可以)
1.2.2排除字符组
纵向模糊匹配,还有一种情形就是,某位字符串可以是除了 a b c 之外的任意字符。这时就是排除字符组的概念。[^abc],表示是一个除了 a b c 之外的任意一个字符。字符组的第一位放 ^(脱字符),表示求反的概念。
1.2.3常见的简写形式
在了解过字符组的概念之后,一些常见的符号也就理解了。他们都是正则中自带的简写形式。
字符组 | 概念 |
---|---|
\d | 数字 |
\D | 非数字 |
\w | 数字,字母,下划线 [0-9a-zA-Z] |
\D | 非数字 |
\W | \w 取反 |
\s | 表示 [ \t\v\n\r\f]。表示空白符,包括空格、水平制表符、垂直制表符、换行符、回车符、换页 符。记忆方式:s 是 space 的首字母,空白符的单词是 white space |
\S | 表示 [^ \t\v\n\r\f]。 \s 取反 |
\n | 换行 |
. | 表示 [^\n\r\u2028\u2029]。通配符,表示几乎任意字符。换行符、回车符、行分隔符和段分隔符 除外。记忆方式:想想省略号 … 中的每个点,都可以理解成占位符,表示任何类似的东西 |
思考一下,如果要匹配任意字符怎么写?
[\d\D] [\w\W] [\s\S] [^]
1.3量词
量词就是数量的意思,也称重复。上面讲了 {m,n} 的含义,这里要记一些简写形式
1.3.1量词的简写形式
量词 | 概念 |
---|---|
{m,} | 表示至少出现 m 次 |
{m} | 等价{m,m} ,表示出现 m 次 |
? | 等价 {0,1} 表示出现或不出现记忆方式:问号的意思表示,有吗? |
+ | 等价{1,} 表示至少出现一次记忆方式:加号表示追加的意思,得先有一个,然后才能追加。 |
* | 等价 {0,} 表示出现任意次,也可能不出现记忆方式:天上的星星,可能一颗都没有,可能几颗,可能多的数不过来 |
// 看一个正则,解读一下
const regex = /a{1,2}b{3,}c{4}d?e+f*/;
1.3.2贪婪匹配与惰性匹配
const regex = /\d{2,5}/g;
const str = '123 1234 12345 123456 1234567';
str.match(regex);// 6个
正则表示数字连续出现 2 到 5 次。
但是其是贪婪的,他会尽可能多的匹配。能匹配到多少就匹配多少。
而惰性匹配,就是尽可能少的匹配:
const regex = /\d{2,5}?/g;
const str = '123 1234 12345 123456 1234567';
str.match(regex);// 11个
这里的正则表示,2 到 5 个都可以匹配。但是当 2 个就够的时候,就不再往下尝试了。
通过在量词后买你加问好就能实现惰性匹配,所有惰性匹配情形如下:
贪婪量词 | 惰性量词 |
---|---|
{m,n} | {m,n}? |
{m} | {m,}? |
? | ?? |
+ | +? |
* | *? |
对惰性匹配的记忆方式是:量词后面加个问号,问一问你知足了吗,很贪婪吗?
1.4 多选分支
一个模式可以实现横向和纵向模糊匹配。而多选分支可以支持多个子模式任选其一。
具体形式: (p1|p2|p3),其中 p1、p2、p3 是子模式,用 | 管道符分割,表示其中任何之一。
例如匹配字符串 ‘ab’ 和 ‘cd’ 可以使用 /ab|cd/
const regex = /ab|cd/g;
const str = 'ab sdfs, cd sagfasf';
str.match(regex);// ..
const regex2 = /good|goodbay/g;
const str2 = 'goodbay';
str2.match(regex2);// ..
const regex2 = /goodbay|good/g;
const str2 = 'goodbay';
str2.match(regex2);// ..
// 这说明了什么?
上面的实例,
说明分支结构也是惰性的,当前面的匹配上了,后面的就不再尝试了
1.5案例分析
以上讲了匹配字符,无非就是字符组,量词和分支结构的组合而已。
1.5.1匹配 16 进制颜色值
// 匹配 颜色值
// 分析 16 进制字符,可以使用字符组 [0-9a-fA-F]
// 字符可以出现 3 次或 6 次,需要使用量词和分支结构(这里一定要注意先后顺序)
const regex = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g;
const str = '#ddd #1fsd34 #FFF #fc0DED';
str.match(regex);
1.5.2匹配时间
// 要求匹配 24 小时制 23:59 01:07
// 分析: 四位数字,第一位为0-2
// 当第一位为 2 第二位为 0 1 2 3 其他情况 第二位为 [0-9]
// 第三位数字 [0-5] 第四位 [0-9]
const regex = /^([01][0-9]|[2][0-3]):[0-5][0-9]$/;
regex.test('23:59');
regex.test('01:07');
// 可以匹配 1:7
const regex = /^(0?[0-9]|1[0-9]|[2][0-3]):(0?[0-9]|[1-5][0-9])$/;
以上使用了 ^ 和 $ ,分别表示字符串的开头和结尾。客观不要着急,下一大章节会学习到
1.5.3匹配日期
比如 yyyy-mm-dd 格式匹配 :2022-08-02
// 分析:年 四位数字 可用 [0-9]{4}
// 月:(0[1-9]|1[0-2])
// 日:(0[1-9]|[12][0-9]|3[01])
const regex = /^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/;
regex.test('2022-08-02');
1.5.4window 操作系统文件路径
// D:\study\react-admin-app\package.json
// D:\study\react-admin-app
// D:\study
// D:\
// 分析: 磁盘:D:\ 使用 [a-zA-Z]:\ (磁盘名称不区分大小写,这里注意 \ 需要转义)
// 文件夹名: 不能包括一些特殊字符 可以使用排除字符组 [^\:*<>|"?\r\n/]
// 而且名字不能为空,至少有一个字符,也就是要使用量词 + 。
// 因此匹配文件夹\ ,可用 [^\:*<>|"?\r\n/]+\
// 而且 文件夹可以出现任意次,([^\:*<>|"?\r\n/]+\)*
// 最后一部分可以是 文件夹没有\ 因此需要添加 ([^\:*<>|"?\r\n/]+)?
const regex = /^[a-zA-Z]:\([^\:*<>|"?\r\n/]+\)*([^\:*<>|"?\r\n/]+)?$/;
regex.test('D:\study\react-admin-app\package.json')
regex.test('D:\study\react-admin-app')
regex.test('D:\study\')
regex.test('D:\')
1.5.5 匹配 id
// <div id="myId" class="my-class"></div>
// 提取出 id="container"
// 最开始的想法
const regex = /id=".*"/g; // 思考下有什么缺点
// . 是通配符,本身就匹配双引号,而量词 * 又是贪婪的,直到遇到最后一个"才会停下来。
// 会把class 一块匹配进来。怎么解决?
// 使用惰性匹配
const regex2 = /id=".*?"/
const str = '<div id="myId" class="my-class"></div>';
str.match(regex2)[0];
const regex3 = /id="[^"]*"/;
str.match(regex3)[0];
在学习到这里的时候,我们已经学会了字符组和量词,已经可以解决大部分常见的情形。到这里的学习,JavaScript 正则已经算是入门了。
未完,待续