例子详解正则表达式(二)
前言
接着例子详解正则表达式(一)往下讲。
1.特殊字符:.
(小数点)
|字符|匹配规则|
|:--:|--|
|.|(小数点)匹配除换行符之外的任何单个字符。例如,/.n/将会匹配 "nay, an apple is on the tree" 中的 'an' 和 'on',但是不会匹配 'nay'。|
直接上例子:
var str="nay, an apple is on the tree";
// g标志表示全局搜索
var pattern = /.n/g; // 匹配字符串中的一个2字节子串,由一个非换行符字符+n
console.log(str.replace(pattern, 'N')); // nay, N apple is N the tree
2.特殊字符:(x)
|字符|匹配规则|
|:--:|--|
|(x)|匹配 'x' 并且记住匹配项,就像下面的例子展示的那样。括号被称为 捕获括号。模式 /(foo) (bar) \1 \2/ 中的 '(foo)' 和 '(bar)' 匹配并记住字符串 "foo bar foo bar" 中前两个单词。模式中的 \1 和 \2 匹配字符串的后两个单词。注意 \1、\2、\n 是用在正则表达式的匹配环节。在正则表达式的替换环节,则要使用像 $1、$2、$n 这样的语法,例如,'bar foo'.replace( /(...) (...)/, '$2 $1' )。|
补充说明:正如上面的说的,()
可以记住第一次匹配到的字串,并依次将记住的字串放在一个列表里面,然后用 \x (x = 0,1,2,3……)
可以访问列表里面的子串,用在正则表达式里面,比如上面表格中的例子/(foo) (bar) \1 \2/
中的(foo), 他第一次匹配到的子串一定是 "foo" (假定父字符串中有foo),那么foo就会被记录在一个列表,然后因为foo是第一个被匹配的,所以用\1可以访问到它,所以其实上面的正则表达式等价于/foo bar foo bar /
,然后肯定会疑惑,为什么不直接这样写?看下面例子:
var str1 = "foo foo",
str2 = "fooo fooooo",
str3 = "foo fo";
var pattern = /(fo*) \1/;
console.log(str1.replace(pattern, "FO*")); // 输出FO*
console.log(str2.replace(pattern, "FO*")); // FO*oo
console.log(str3.replace(pattern, "FO*")); // foo fo
先看上面str1的输出,是FO*
,你会发现 foo foo
全部被 FO*
替换。这不就相当于父串被 /fo* foo/
匹配了吗?换言之 \1
等价于 foo
,然后 fo*
第一次匹配的正是 foo foo
中的 foo
。
再看str2,输出的是 FO*oo
,被替换掉的部分是:fooo fooo
。那么上面代码中的pattern就相当于 /fo* fooo/
。
再看str3,是原样输出,为什么呢?pattern
中 fo*
第一次匹配到的字串是 foo
,那么pattern就等价于 /fo* foo/
,显然父串中并没有匹配项,因此原样输出。
小结:带()
特殊字符的正则表达式,会对父串匹配两次。第一次匹配是为了将每个记录放进”列表“中,然后解析当前正则表达式为"真"正则表达式(解析当前正则表达式中的\x x=123..n
),第二次才开始真正的匹配。
3.特殊字符:(?:x)
|字符|匹配规则|
|:--:|--|
|(?:x)|匹配 'x' 但是不记住匹配项。这种叫作非捕获括号,使得你能够定义为与正则表达式运算符一起使用的子表达式。来看示例表达式 /(?:foo){1,2}/。如果表达式是 /foo{1,2}/,{1,2}将只对 ‘foo’ 的最后一个字符 ’o‘ 生效。如果使用非捕获括号,则{1,2}会匹配整个 ‘foo’ 单词。|
补充说明:该字符和第二个特殊字符的作用有点类似,但是不同的是:该字符没有”记住“的能力。他存在意义正如表格中的介绍:
表达式是 /foo{1,2}/,{1,2}将只对 ‘foo’ 的最后一个字符 ’o‘ 生效。
ps:{1, 2}的意思是:至少前面的字符至少出现1~2次,比如?可以写成:{0, 1}
var str1 = str2 = "many foofoofoo";
var pattern1 = /(?:foo)+/, // 匹配父串中的 foo...foo或foo
pattern2 = /foo+/; // 匹配父串中的foo...o或foo
console.log(str1.replace(pattern1, "FOO")); // 输出many FOO
console.log(str2.replace(pattern2, "FOO")); // 输出many FOOfoofoo
说道这里,我补充一点比较重要的知识点(不论你有没有明白到这一点):正则表达式在匹配父串的时候,是逐个字符去匹配,以每个字符作为一个单位
小结:(?:x)
是将 x
作为一个单位去匹配父串
- 各位观众老爷,今天就到这里,且听下回分解。
附录
字符 | 作用 |
---|---|
g | 全局搜索。 |
字符 | 匹配规则 |
---|---|
{n,m} | n 和 m 都是正整数。匹配前面的字符至少n次,最多m次。如果 n 或者 m 的值是0, 这个值被忽略。例如,/a{1, 3}/ 并不匹配“cndy”中得任意字符,匹配“candy”中得a,匹配“caandy”中得前两个a,也匹配“caaaaaaandy”中得前三个a。注意,当匹配”caaaaaaandy“时,匹配的值是“aaa”,即使原始的字符串中有更多的a。 |