问号在JavaScript正则表达式中的作用

Author : lovecicy

对于JS的正则表达式,一般都是用到的时候再看看,用完了就忘了,所以对于一些比较复杂的正则表达式,经常要对着手册看个半天才能看明白。今天照着MDN的手册,仔细看了一遍,争取下次不翻手册。

关于正则表达式的学习,玉伯推荐了一个网站,非常全面,有兴趣的同学可以看看——Regex Tutorial。但是是全英文的,而且JS的正则表达式引擎其实只实现了部分的正则表达式功能,比如后向匹配的功能就没有实现,所以要说如果要学JS的正则表达式,还是MDN的手册更简单、方便。这里再推荐一个学习正则的好地方:Debuggex,看下面的例子就知道了。

    ^My.*[^!.?]$

Regular expression visualization

Debuggex Demo

看完手册,唯一的感觉就是,问号太重要了,大多数复杂的正则表达式,一般有问号的参与,而且各种组合,稍微不用心就会记混掉,所以今天就来整理下问号在JS正则表达式中的作用。

1. 单个问号

Matches the preceding character 0 or 1 time. Equivalent to {0,1}.
匹配前面的字符0次或1次,与{0,1}的作用相同。

For example, /e?le?/ matches the ‘el’ in “angel” and the ‘le’ in “angle” and also the ‘l’ in “oslo”.
比如/e?le?/匹配”angel”中的’el’,”angle”中的’le’,也匹配”oslo”中的’l’。

If used immediately after any of the quantifiers *+?, or {}, makes the quantifier non-greedy (matching the minimum number of times), as opposed to the default, which is greedy (matching the maximum number of times). For example, using /\d+/ non-global match “123abc” return “123”, if using /\d+?/, only “1” will be matched.
如果问号直接跟在量词*, +, ?或者{}的后面,会让量词进入非贪婪模式(匹配最少的次数),和默认的贪婪模式(匹配最多的次数)正好相反。比如,用/\d+/匹配”123abc”会返回”123″,但是如果用/\d+?/,则只会匹配”1″。

 

单个问号有两个作用,一:作为量词,匹配0个或1个前面的字符;二:表示非贪婪

2. 非捕获((?:x))

Matches ‘x’ but does not remember the match. These are called non-capturing parentheses. The matched substring can not be recalled from the resulting array’s elements [1], …, [n].
匹配’x’但是不记住这次匹配。这被称为非捕获括号。被捕获的子字符串不能通过结果数组的[1]……[n]来访问。

要理解非捕获,必须先要理解捕获。”(x)”被称为捕获括号,它会匹配括号内的内容,并将括号内的内容记住。比如我们可以用”\b(\w+)\b\s+\1\b”来匹配类似”go go”,”hello hello”之类的重复单词,其中的’\1’代表之前被捕获的'(\w+)’。

可以看下面的例子:

"abcdabceabcdcba".match(/(abc)d(cba)/)
结果:["abcdcba", "abc", "cba"]
"abcdabceabcdcba".match(/(abc)d(?:cba)/)
结果:["abcdcba", "abc"]

上面的例子可以看到捕获和非捕获的区别,非捕获的'(?:cba)’不能在结果数组中访问,问捕获的'(cba)’则可以。

3. 前向断言(x(?=y))

Matches ‘x’ only if ‘x’ is followed by ‘y’. This is called a lookahead.
仅在’x’后面紧跟着’y’时匹配’x’,这就是前向断言。

For example, /Jack(?=Sprat)/ matches ‘Jack’ only if it is followed by ‘Sprat’. /Jack(?=Sprat|Frost)/ matches ‘Jack’ only if it is followed by ‘Sprat’ or ‘Frost’. However, neither ‘Sprat’ nor ‘Frost’ is part of the match results.
举例来说,/Jack(?=Sprat)/仅在’Jack’后跟着’Sprat’时匹配’Jack’。/Jack(?=Sprat|Frost)/仅在’Jack’后面跟着’Sprat’或者’Frost’时匹配’Jack’。然而,’Sprat’或者’Frost’都不是匹配结果的一部分。

前向断言的作用是匹配后面跟有y的x,但是不返回y。

4. 负前向断言((x(?!y)))

Matches ‘x’ only if ‘x’ is not followed by ‘y’. This is called a negated lookahead.
仅在’x’后面没有’y’时匹配’x’,这就是负前向断言。

For example, /\d+(?!\.)/ matches a number only if it is not followed by a decimal point. The regular expression /\d+(?!\.)/.exec("3.141") matches ‘141’ but not ‘3.141’.
比如,/\d+(?!\.)/匹配一个后面不带小数点的数字。/\d+(?!\.)/.exec(“3.141”) 执行的结果是返回’141’而不是’3.141’。

同前向断言类似,负前向断言的作用是匹配后面不跟有y的x。


对于JS正则表达式中的问号就介绍到这里,其他特殊字符,由于比较容易理解,这里不做介绍。虽然单个的特殊字符很容易理解,但是要写出符合实际要求的正则表达式还是需要不断的实践。以上理解如有不对的地方,欢迎不吝赐教。

standard
  1. lovecicy - 2014 年 2 月 13 日 6:13 下午

    这是斜体

    回复
  2. Yu - 2014 年 2 月 21 日 8:27 下午

    you can use markdown to write your comment here.

    have fun

    回复

Have your say