今天的这篇是补更的上周的内容,对于几乎迟到了整整一周的这件事,我感到很惭愧,因为自己没能很好的平衡工作和个人事务之间的关系。废话不多说,下面进入正题
很多语言中都有对正则表达式的支持,javascript 也不例外。虽然我们经常听说正则,但是实际使用中却很少回去使用,原因无他——不会。所以今天我们就一起来认识一下正则表达式
什么是正则表达式(Regular Expression)?
使用单个字符串来描述、匹配某种规则的字符串
正则表达式
正则表达式由两种基本字符类型组成:原意文本字符和元字符
元字符是在正则表达式中含有特殊含义的非字母字符,如:
. * + ? $ ^ | \ ( ) { } [ ]
当然,元字符并不止上面这些,还有 \t \b
等等
字符类
在正则中的一个字符对应着字符串中的一个字符,如:
ab\t
=> ab // 最后一个为 tab 水平制表符
但是往往我们需要表示的并不只是单独的一个字符,而可能是一类具有某种特征的字符,这时可以通过构建一个字符类来达到目的
[abc] // [abc] 为一个整体,只对应字符串中的一个字符
=> a
=> b
=> c
上面的例子就通过构建了一个 [abc]
字符类达到了匹配 a
或 b
或 c
的目的
如果要不匹配某一类字符的话,可以在中括号内的最前面添加 ^
来达到取反的目的
[^abc] // 不匹配 a 或 b 或 c
范围类
如果我们需要匹配一个数字,使用字符类可能会这样写 [0123456789]
,但是通过范围类可以达到很简单的书写方式
[0-9] // 匹配数字
[a-z] // 匹配小写英文字母
[a-zA-Z] // 匹配所有英文字母
范围类本身是一个闭区间,包括了范围的两头;同时也可以通过连写达到其他的匹配目的
但是-
本身并不是特殊字符,只有在两个文本字符之间时才能有表示范围的作用。那如果我们需要匹配-
该怎么办呢?
[0-9-] // 在最后加上 - ,从而达到匹配 0123456789- 的目的
预定义类
对于常用的范围类,正则为我们提供了一些同样作用的预定义类,如 [0-9]
等价于 \d
,常用的有以下这些:
. => [^\r\n] // 除回车和换行符之外的所有字符
\d => [0-9] // 所有数字
\D => [^0-9] // 所有非数字
\s => [\t\nx0B\f\r] // 空白符
\S => [^\t\nx0B\f\r] // 非空白符
\w => [a-zA-Z_0-9] // 单词字符(字母数字下划线)
\W => [^a-zA-Z_0-9] // 非单词字符
边界匹配
^ // 以xxx开始 (在中括号中表示取反)
$ // 以xxx结束
\b // 单词边界
\B // 非单词边界
举例说明:
^ac\d
// 匹配以 a 开头,第二个字符为 c,第三个字符为数字的字符串,如 ac0 ac1r ac2fds 的前3个字符将会被匹配
// bc0d ba13fsd b0adas 等将不会被匹配
\di9$
// 匹配以 9 结尾,倒数第二个字符为 i,倒数第三个字符为数字的字符串,如 das0i9 12i9 r324i9 的最后3个字符将会被匹配
\bf\dk\b
// 只匹配以 f 开头 k 结尾 中间是数字的三位字符串 f0k f1k f2k
// af1k f1k3 f9i 等将不会被匹配
\bf\dk\B
// 只匹配以 f 开头,中间是数字,第三位是 k 且 k 不是结尾的字符串 f0k1 f0kkk f2k22
// f0k f1k f2k fkk fkf fkk0 等将不会被匹配
量词
如果需要匹配一个十位数字,可能会这样写
\d\d\d\d\d\d\d\d\d\d
但也可以像下面这样写
\d{10}
{10}
就是一个量词描述
量词有下面这些
? // 最多出现一次 a?
+ // 最少出现一次 a+
* // 出现任意次 a*
{n} // 出现 n 次 a{3}
{n,m} // 出现 n 到 m 次 a{1,3}
{n,} // 至少出现 n 次 a{2,}
// 不存在 {,m} 的写法,它等同于 {0,m}
贪婪模式与非贪婪模式
如果有字符串12345678
,有正则\d{3,6}
,那么它会如何匹配呢?
正则在匹配的时候回尽可能多的匹配,所以上面的这个正则只会匹配到123456
,78
将不会被匹配,这叫正则表达式的贪婪模式
如果我们想要正则只要匹配到就不在继续匹配,就要使用正则的非贪婪模式,只需要在两次的后面加上?
就可以了
// 非贪婪模式的正则
\d{3,6}?
// 0123456789 这个字符串将会被匹配到 012 345 678
分组
当有一个单子需要被重复5次时,我们会这样写word{5}
,但是这个正则对应的字符串应该是worddddd
,量词只会将它紧邻的字符重复
所以如果要重复一个整体,就需要将word
作为一个整体:
(word){5}
// wordwordwordwordword
通过()
我们可以达到分组的目的
再举例:单词+数字连续重复3次
([a-zA-Z]\d){3}
// a3f4d2
// j9k0l8
或
需要表示 word 或 number 这两个英文单词时,可以通过|
来表示
(word)|(number)
// word
// number
// 需要注意的是不能写成 word|number 否则会匹配 wordumber 或者 wornumber
反向引用
当我们匹配一个字符串时,可能会需要获取原字符串中的内容,此时我们可以这样做
// 原字符串
2017-10-14
// 正则
(\d{4})-(\d{2})-(\d{2})
// 需要转换成 10/14/2017 的格式,反向引用的表达式
$2/$3/$1
在正则中被分组的字符,我们可以按顺序通过 $1 $2 $3 ...
来捕获,如果需要引用原字符串的内容,只需要引用对应的 $1 $2 $3 ...
即可
如果分组后不想捕获,可以忽略分组,只需要在分组内加上?:
即可
(\d{4})-(?:\d{2})-(\d{2})
// 中间的第二个分组将会被忽略,原先的 $2 现在会获取到原先 $3 对应的值
前瞻后顾
正则在匹配到规则的时候,向前检查是否符合断言叫前瞻,向后检查则叫后顾
文本的尾部为前,头部为后
其中 js 不支持后顾
符合肯定断言叫正向匹配,不符合叫负向匹配
// assert 为断言正则
// 正向前瞻
exp(?=assert)
//负向前瞻
exp(?!assert)
//正向后顾
exp(?<=assert)
//负向后顾
exp(?<!assert)
前瞻后顾不会被匹配,它只是作为是否匹配成功的一个条件
\w(?=\d)
// 匹配一个单词字符,如果这个字符后面是一个数字,则这个字符匹配成功,否则失败
// a1 匹配到 a
// _0 匹配到 _
// a2b3 匹配到 a b
// *0 由于第一个字符不是单词字符,匹配失败
// aa 由于第二个字符不是数字,匹配失败
扫码关注前端周记公众号正则表达式的学习可以有厚厚的一本书,如果想要深入学习正则的话,本篇文章的这点内容肯定是不够的
但是作为提升我们平时开发效率的工具而言,掌握住上面这些也基本够用了
下一篇(明天)我们来一起学习在 javascript 中如何使用正则表达式
网友评论