Discuss / JavaScript / 第二题

第二题

Topic source
var re = /^<\w+\s\w+>\s\w+@\w+\.com|org$/;
re.test('<Tom Paris> tom@voyager.org');
true

这个匹配通过,可是改成这样后

var re = /^<(\w+\s\w+)>\s(\w+@\w+\.com|org)$/;

为什么取子串的时候就有问题了?

只是加了2对()而已

LevonLin

#3 Created at ... [Delete] [Delete and Lock User]

这和分支符号|的优先级比较低有关。 /^<s\w+>\s\w+@\w+\.com|org$/实质被|分为^<\w+\s\w+>\s\w+@\w+\.comorg$; /^<(\w+\s\w+)>\s(\w+@\w+\.com|org)$/后面那组则被分为\w+@\w+\.comorg 所以第一个正则之所以为true只是因为表达式取org$时侥幸匹配了"org"这三个字符;而第二个正则加了分组后必须匹配"<Tom Paris> org"这种形式的字符串,然而那个邮箱里根本没有这种形式的子串嘛,你test()一下一定得到false

但要解决你的问题我们还得理解一下exec(),站长说

exec()方法在匹配成功后,会返回一个Array,第一个元素始终是原始字符串本身,后面的字符串表示匹配成功的子串。

其实并不是很准确,Array的第一个元素应该只有原始字符串中被正则匹配的那一部分,而非全部。举个例子:

var re = /^(w+)@\w+\.com|(org)$/;
re.exec('tom@voyager.org')[0]; //结果为"org,,org"

可见,第一个元素"org"确实只是被正则匹配的那一部分;同时也能看出Array里后面所谓按分组匹配成功取得的子串也是相对被正则整体匹配的部分字符串而言的,所以那个(\w+)才匹配不到而显示为空。

现在结论就很明显了,因为你第二个正则根本匹配不到什么字符,所以对依赖被正则匹配的那一部分来进行子串分割的exec()自然不能正常使用。验证:

var re = /^<(\w+\s\w+)>\s(\w+@\w+\.com|org)$/;
re.exec('<Tom Paris> tom@voyager.org').toString(); //Uncaught TypeError: Cannot read property 'toString' of null

要让你第二个正则能用就要加括号提升|的优先级,但是加括号意味着加分组,会让exec()出现意想不到的结果,所以最终结论就是别这么写咯~


  • 1

Reply