复习正则表达式
最近研究ES6, 正好ES6也有正则方面的内容, 看看有什么新特性, 顺便又把
精通正则表达式
拿出来粗看了前面几章节, 于是给自己出了几道题. 还做了一点总结.
[\b]
和\b
和\B
一般作为初学者看到这么多这些鬼都会头大了. 下面我将详细讲解一下.
[\b]
- 退格符
另外其实我一直都搞不清楚[\b]
匹配一个退格(U+0008)
是什么鬼. 似乎没有人告诉我这个退格符长什么样. 我也不知道那些各种转载各种规则的人他们自己知不知道是啥... (难道就我不知道- -)
找了半天, 总算在MSDN: 正则表达式语言 - 快速参考找到了示例. 难道就是匹配\b
用的吗?, 当然很明显的区别是, 它属于字符转义
\b
- 一个词的边界
MSDN: 匹配必须出现在\w
(字母数字)和\W
(非字母数字)字符之间的边界上。
这个就很好理解了, 会写先行断言的我当然是知道了, 他不占用任何位置, 边界一般都是单词或数字两边, 更为具体的通过MDN的正则表达式文档\b
介绍内的注意有指引, 查到ecma文档的15.10.2.6 Assertion中IsWordChar
处, 不过由于个人能力有限, 对其理解如下:
通过这段代码(正则表达式案例分析 (一) - (3) 单词边界):
"I'd prefer p2p O_O".replace(/\b/g,function(){
console.log(arguments)
});
输出结果:
{ '0': '', '1': 0, '2': 'I\'d prefer p2p O_O' }
{ '0': '', '1': 1, '2': 'I\'d prefer p2p O_O' }
{ '0': '', '1': 2, '2': 'I\'d prefer p2p O_O' }
{ '0': '', '1': 3, '2': 'I\'d prefer p2p O_O' }
{ '0': '', '1': 4, '2': 'I\'d prefer p2p O_O' }
{ '0': '', '1': 10, '2': 'I\'d prefer p2p O_O' }
{ '0': '', '1': 11, '2': 'I\'d prefer p2p O_O' }
{ '0': '', '1': 14, '2': 'I\'d prefer p2p O_O' }
{ '0': '', '1': 15, '2': 'I\'d prefer p2p O_O' }
{ '0': '', '1': 18, '2': 'I\'d prefer p2p O_O' }
我们看到被断掉(用|
表示)的位置分别是:
也就是说连续的单词
和数字
和_
组合(上文提到的ecma部分的表格也对应了这个)都是一个单位, 他的两侧就是截断. 除此之外的任何符号都会截断他们.
另外, 在MSDN文档中, 它被归为定位点
.
\B
- 一个非单词边界
前面说了这么多, \B
的理解就很轻松了, 一个非单词边界. 就不多说了, 看看MSDN的例子就清楚了.
模式: \Bend\w*\b
原字符串: end sends endure lender
匹配结果: ends
和ender
关于正则个人的经验
其实搞正则匹配, 我个人的从精通正则表达式书中阅读后的感受就是, 匹配一定要一个个看, 慢慢的看, 比如上面这个例子, 我看看模式先是
\B
, 然后再找原字符串, 依次步骤分析:
- 第一个
e
左边(位置)是边界不符合, 失败看下一个字符- 第二个
n
左边(位置)符合\B
, 匹配成功, 再看模式\B
后面的e
- 模式
\B
(位置)后面的e
不匹配n
, 失败再看下一个字符d
- 第三个
d
左边(位置)符合\B
, 匹配成功, 再看模式\B
后面的e
- 模式
\B
(位置)后面的e
不匹配第三个字母d
, 失败再看下一个字符(这里是个空格啦?)
- ...(此处省略, 一直到
send
单词)- (前面都不符合,当遇到了
send
), 经过一步步后移, 模式\B
(位置)走到了s
右侧, 成功! 此刻, 兴奋的将模式移到第二个e
- 好巧, 模式中的
e
匹配到s
后面的字符e
, 再回到模式下一位n
- 世界太小了, 又一次成功了, 紧接着是
d
, 看起来一一对应上了- ...(截至目前,
\Bend
部分已经和sends
中的end
配上了, 可是还没完呢)- 模式
d
后面是\w*
, 我们回到原字符串部分send
后面是s
所以也成功了- 再看模式部分
\w*
下一位\b
, 碰到上面讲的单词边界了( •̀ ω •́ )y, 我们看看原字符串部分sends
这里的确被截断了, 因此原字符串开始新一轮匹配- ...(反复如上步骤)
最后就得出了匹配结果的两组字符串了. 不知道我这样讲大家能不能理解, 或者说这种思路大家有没有疑问和反对之处, 如果有希望大家留言?
两道正则题目
自己折磨自己
题一: 找出符合规则的时间
匹配符合标准格式的时间. 这是内容部分:
now is 09:4 am test
now isx9:4 am test
now isx2:54 am test
now isA09:04 amwtest
now is_12:30 pm adsadadasda
now is 21:59 amdsadasdwq
now is 22:75 am_dsad21
now is 41:60 pm dsadsad
now is 26:23 am dwadwq
now is 2a:23 am dwadwq
期望结果(虽然24小时制后面存在[ap]m感觉还是不太合理.)
09:4 am
9:4 am
2:54 am
09:04 am
12:30 pm
21:59 am
看起来应该不是很复杂. 结果我写了一天没写出来. 因为我不知道怎么剔除26
. 似乎无论怎么写, 在2
和6
之间正向断言始终都会匹配到6
. ES5却是不支持后行断言(negative lookbehind)的, 据说ES6支持后行断言了, 才得以解决这个问题, 然而不通过后行断言来处理这个问题, 我始终没有写出来, 难道真的是实现不了?
这是一个未能完美解决的其中一种写法.
/([01]\d|(?=2(?![4-9]))2\d?|(?!2)\d):(0?(?=\d)[0-9]|[1-5][0-9])(\s*[a|p]m)/gim
这是通过后行断言的写法:
/([01]\d:|(?=2(?![4-9]))2\d?:|(?
题二: 找出文件后缀名
再来看另一个, 获取文件后缀名的正则写法问题:
可能有以下文件, 需要准确获取每个文件的文件类型, 例如:
a.jpg
hello world.png
c.c.mp3
_do_(it)._unknow
期望:
.jpg
.png
.mp3
._unknow
这个其实还算按比较简单的了. 不过在我复习正则之前硬是想不起来咋写, 稍微过了一遍再写就容易多了. 正则写法\..(?!\.).*
.
改题目来源于前几天同事发的一个javascript自验网站: ScriptOJ首页的题目.
关于题目部分, 不知道大家也有没有更好的写法, 也欢迎大家探讨纠正哦?