6
var email = '[John Smith] <johnsmith@gmail.com>';

var re1 = /.*<+(.*)+>.*/;
var re2 = /.*\[+(.*)+\].*/;

var address = email.replace(re1, "$1");
var name = email.replace(re2, "$1");

我发现第二个正则表达式(获取名称)运行速度非常慢。但第一个很好。为什么会这样,有没有更好的方法来获取我需要的字符串?

4

3 回答 3

16

你的正则表达式很慢的原因是因为它们写得很糟糕

现在,让我们继续说他们为什么不好。

您的第一个表达式有一堆不必要的标记。例如领先和落后.*- 它们没有区别。其次,您已经量化了<0 到 inf 的时间。为什么?你想匹配<<<<<<<<email>吗?还是email>?最后,您已经量化了一个重复组。这太可怕了,因为

  1. 量化的捕获组将覆盖自身
  2. 由于上面的陈述,使用捕获组没有意义,因此它使用了不必要的资源。

好吧,这是第一个表达。第二个更糟糕,即使你刚刚切换<>[]. 为什么你可能会问?我会告诉你为什么。因为它不匹配。你可能会问,为什么情况如此糟糕?因为它会产生我们所说的灾难性回溯。你可能想知道为什么它会这样做?我会告诉你为什么:

.*会尽量匹配。实际上,起初它会消耗整个字符串。显然这失败了,所以它回溯了很多次,直到它可以匹配第一个[. 太棒了,现在引擎已经在字符串的第一个位置找到了一个匹配的字面量[(从而使.*匹配什么都没有)。现在下一个令牌,.*由于其贪婪的性质,将再次匹配所有内容。这不起作用,因此引擎回溯。它将继续尝试这样做,直到它与字符串匹配。问题是,它永远不会。因为您的贪婪量词被一个需要1个或多个匹配的量化组包围。

现在,你如何解决这个问题?好吧,您可以简单地+从组后面删除。那会解决它。您的正则表达式仍然很糟糕,但它们不会导致引擎回溯一百万次。我们如何才能进一步改进它?通过使用否定字符类。

/\[([^]]+)\] <([^>]+)>/

在此处查看正则表达式的演示:http ://regex101.com/r/wS2jN0

如果您使用 regex101.com 开始,您会立即注意到回溯问题:http ://regex101.com/r/vB8xB0

于 2013-01-07T00:14:28.740 回答
4

不确定您的性能问题(如果有),但您可以使用单个正则表达式来提取两个值:

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"
于 2013-01-06T23:59:34.173 回答
3

这是由于使用了许多贪婪.*的 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
于 2013-01-07T00:25:56.770 回答