对于一门语言的掌握程序怎么样?可以有两个角度来衡量:读和写。不仅要求自己能解决问题,还要能看懂别人的解决方案,代码是这样,正在表达式也是这样。
正则这门语言跟其他语言有一点不同,它通常就是一大堆字符,而没有所谓“语句”的概念。 如何能正确地把一大串正则拆分成一块一块的,成为了破解“天书”的关键。
这篇文章提供的答案:
- 结构和操作符的优先级 ?
结构和操作符
编程语言一般都有操作符。只要有操作符,就会出现一个问题。当一大堆操作在一起时,先操作谁,又后操 作谁呢?为了不产生歧义,就需要语言本身定义好操作顺序,即所谓的优先级。
而在正则表达式中,操作符都体现在结构中,即由特殊字符和普通字符所代表的一个个特殊整体。
JavaScript 正则表达式中,都有哪些结构呢?
字符字面量、字符组、量词、锚、分组、选择分支、反向引用。
具体含义简要回顾如下:
结构 | 说明 | |
---|---|---|
字面量 | 匹配一个具体字符,包括不用转义的和需要转义的。比如 a 匹配字符 "a", 又比如 \n 匹配换行符,又比如 . 匹配小数点。 | |
字符组 | 匹配一个字符,可以是多种可能之一,比如[0-9] ,表示匹配一个数字。也有\d 的简写形式。另外还有反义字符组,表示可以是除了特定字符之外任何一个字符,比如[^0-9] 。表格一个非数字字符,也有\D 的简写形式。 |
|
量词 | 表格一个字符连续出现,比如a{1,3} 表示,"a" 字符连续出现3次。另外还有常见的简写形式,比如a+ 表示"a" 字符连续出现至少一次。 |
|
锚 | 匹配一个位置,而不是字符,比如^ 匹配字符串的开头,又比如\b 匹配单词边界。又比如(?=\d) 表示数字前面的位置。 |
|
分组 | 用括号表示一个整体,比如(ab)+ 表示ab 两个字符连续出现多次,也可以使用非捕获分组,(?:ab) 。反向引用,比如\2 表示引用第二个分组 |
|
分支 | 多个子表达式多选一,比如`abc | bcd,表达式匹配 abc或者 bcd`字符子串。 |
而其中涉及到的操作符有:
操作符描述 | 操作符 | 优先级 | |
---|---|---|---|
转义符 | \ |
1 | |
括号和方括号 |
(…) 、(?:…) 、(?=…) 、(?!…) 、[…]
|
2 | |
量词限定符 |
{m} 、{m,n} 、{m,} 、? 、* 、+
|
3 | |
位置和序列 |
^ 、$ 、\元字符 、一般字符
|
4 | |
管道符(竖杠) | ` | ` | 5 |
上面操作符的优先级从上至下,由高到低。
下面拆分一个例子:
/ab?(c|de*)+|fg/
- 由于括号的存在,所以,
(c|de*)
是一个整体。 - 在其中,由于管道符的存在,里面是一个分支结构。所以
c
是一个整体,de*
是一个整体 - 而
de*
中由于量词的存在,所以e
是一个整体 - 同理,整个正则分成了
a
、b?
、(c|de*)+
、f
、g
。 - 由于分支的存在,又整体分为
ab?(c|de*)+
、fg
两个部分。
注意要点:
关于结构和操作符,还是有几点需要强调:
1.匹配字符串整体问题
因为是要匹配整个字符串,我们经常会在正则前后添加^
和$
。
例如要匹配abc
或者bcd
,如果不小心就可能写成/^abc|bcd$/
.
但是位置字符和字符序列优先级要比竖杠高,故其匹配的结构是:
image.png
所以我们这里要写成这样/^(abc|bcd)$/
.
可以看出两个的差距。
2.量词连缀问题
假设,要匹配这样的字符串:
- 每个字符为
a
,b
,c
任选其一。 - 字符串的长度是3的倍数。
此时正则不能想当然地写成/^[abc]{3}+/
.因为它会报错。
怎么办呢?
给它加个括号,把前面括起来。
image.png3.元字符转义问题
所谓元字符,就是正则中有特殊含义的字符。
所有结构,用到的元字符总结如下:
^、$、.、*、+、?、|、\、/、(、)、[、]、{、}、=、!、:、- ,
当匹配上面的字符本身时,可以一律转义:
var string = "^$.*+?|\\/[]{}=!:-,";
var regex = /\^\$\.\*\+\?\|\\\/\[\]\{\}\=\!\:\-\,/;
console.log( regex.test(string) );
// => true
其中string
中的\
字符也是要转义的。
另外,在string
中,可以把每个字符转义,当然,转义后的结构仍是本身:
var string = "^$.*+?|\\/[]{}=!:-,";
var string2 = "\^\$\.\*\+\?\|\\\/\[\]\{\}\=\!\:\-\,";
console.log( string == string2 );
// => true
4.字符串中的元字符
更字符组相关的元字符,如果需要匹配,也需要进行转义。
var string = "^$.*+?|\\/[]{}=!:-,";
var regex = /[\^$.*+?|\\/\[\]{}=!:\-,]/g;
console.log( string.match(regex) );
// => ["^", "$", ".", "*", "+", "?", "|", "\", "/", "[", "]", "{", "}", "=", "!", ":",
"-", ","]
5.匹配[abc]
和{3,5}
如果要匹配[abc]
和{3,5}
.
可以写成/\[abc]/
或者/\[abc]/
.
var string = "[abc]";
var regex = /\[abc]/g;
console.log( string.match(regex)[0] );
// => "[abc]"
只需要转义第一个方括号就可以,因为后面的构不成字符组。
而匹配{3,5}
则使用/\{3,5}/
.
6.其余情况
比如=
,!
,:
,-
,,
等符号,只要不在特殊结构中,并不需要转义。
但是,括号需要前后都转义/\(123)/
。
至于剩下的 ^、$、.、*、+、?、|、\、/
等字符,只要不在字符组内,都需要转义的。
网友评论