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