var email = '[John Smith] <johnsmith@gmail.com>';
var re1 = /.*<+(.*)+>.*/;
var re2 = /.*\[+(.*)+\].*/;
var address = email.replace(re1, "$1");
var name = email.replace(re2, "$1");
我发现第二个正则表达式(获得名称)运行速度超慢。但第一个很好。为什么会这样,有没有更好的方法来获得我需要的字符串?
答案 0 :(得分:15)
你的正则表达式很慢的原因是因为它们是可怕的写。
现在,让我们继续说明为什么他们不好。
你的第一个表达式有一个束的不必要的令牌。如引导和尾随.*
- 它们没有区别。其次,您已将<
0量化为inf时间。为什么?你想要匹配<<<<<<<<email>
吗?还是email>
?最后,您已经量化了重复组。这太可怕了,因为
好吧,那是第一个表达。第二个更糟糕,即使您刚刚<>
切换[]
。你可能会问为什么?我会告诉你原因。 因为它不匹配。你可能会问为什么这么糟糕?因为它会产生我们称之为灾难性回溯的东西。为什么这样做你可能想知道?我会告诉你原因:
.*
会尝试尽可能匹配。事实上,首先,它将消耗整个字符串。显然失败了,所以它回溯了很多次,直到它可以匹配第一个[
。太棒了,现在引擎在文字[
的字符串的第一个位置找到了一个匹配(从而使.*
没有匹配)。现在下一个标记.*
将再次匹配所有内容,因为它的贪婪性质。这不起作用,因此引擎回溯。它将继续尝试这样做,直到它匹配字符串。问题是,它永远不会。因为你的贪婪量词被一个需要一个或多个匹配的量化组包围。
现在,你如何解决这个问题?好吧,您只需从组后面删除+
即可。那会解决它。你的正则表达式仍然很糟糕,但它们不会导致引擎回溯百万次。我们怎样才能进一步提高它?通过使用否定的字符类。
/\[([^]]+)\] <([^>]+)>/
在此处查看正则表达式的演示:http://regex101.com/r/wS2jN0
如果你开始使用regex101.com,你会立即注意到回溯问题:http://regex101.com/r/vB8xB0
答案 1 :(得分:2)
不确定您的性能问题(如果有)但您可以使用单个正则表达式来提取这两个值:
var str = '[John Smith] <johnsmith@gmail.com>',
re = /\[(.+)\] <(.+)>/,
name = str.match( re )[1],
email = str.match( re )[2];
console.log( name, email ); //=> "John Smith johnsmith@gmail.com"
答案 2 :(得分:2)
这是因为使用了许多贪婪的.*
,结果事实上字符串的格式为"[..] <..>"
。
每次使用.*
而没有?
时,RegExp引擎选择整个字符串的其余部分,然后一次向后移动一个字符,因为RegExp的以下部分失败,测试下一个一部分。
正如您重复.*
一样,这意味着您要告诉它从RegExp引擎必须回溯的字符串末尾开始,为每个字符运行指数级更多的测试。然后,贪婪的+
标志使情况变得更糟,重复了*
重复做的事情。
添加?
s并不是最好的解决方法,因为您对字符串了解得更多,并且您并未在其中寻找那么多内容。因此,为了减少&#34; bad&#34; ,请做一些事情,例如只匹配您感兴趣的位
var re1 = /\<([^>]*)>/,
re2 = /\[([^\]]*)\]/;
var address = email.match(re1)[1],
uname = email.match(re2)[1]; // to avoid `window.name` conflict