此RegEx函数中的内存问题是什么

时间:2015-05-29 20:34:33

标签: javascript regex

我正在尝试抓取电子邮件地址的网页。我几乎有它工作,但似乎有一些巨大的内存错误,使我的脚本加载时页面冻结。

这就是我所拥有的:

var bodyText = document.body.textContent.replace(/\n/g, " ").split(' '); // Location to pull our text from. In this case it's the whole body

    var r = new RegExp("[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])", 'i');
    function validateEmail(string) {
        return r.test(string);
    }

    var domains = [];
    var domain;
    for (var i = 0; i < bodyText.length; i++){
        domain = bodyText[i].toString();
        if (validateEmail(domain)) {
            domains.push(domain);
        }           
    }

我唯一能想到的是我使用的电子邮件验证功能是一个32步表达式,page I'm running it on返回超过3,000个部分,但我觉得这应该是可能的。< / p>

这是一个重现错误的脚本:

var str = "help.yahoo.com/us/tutorials/cg/mail/cg_addressguard2.html"; 
var r = new RegExp("[a-z0-9!#$%&'*+\/=?^_{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_{|}~-]+)*@(?:[a-‌​z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])", 'i'); 
console.log("before:"+(new Date())); 
console.log(r.test(str)); 
console.log("after:"+(new Date()));`

我可以做些什么来克服内存问题?

3 个答案:

答案 0 :(得分:4)

stribizhev已在评论中指出了解决方案:在RegExp literal 语法中指定正则表达式。正如sln的评论所示,另一个解决方案是正确转义字符串文字中的\

我不会说明在这个答案中使用正则表达式验证/匹配电子邮件地址的正确正则表达是什么,因为它已经多次重新进行了重复。

为了演示导致问题的原因,让我们将传递给RegExp构造函数的字符串打印到控制台。您是否注意到某些\丢失了?

[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])
               ^               ^               ^                                                 ^

上面的字符串是RegExp构造函数看到并编译的内容。

  • /只需要在RegExp文字中进行转义(因为RegExp文字由/分隔),并且不需要在字符串传递中转义到RegExp构造函数因此,遗漏不会引起任何问题。

    以下是显示如何编写正则表达式以使/与RegExp文字和RegExp构造函数匹配的等效示例:

    /\//;
    new RegExp("/");
    
  • 但是,由于\中的\.未在字符串中正确转义,而不是匹配文字.,因此它允许任何字符(行分隔符除外)匹配。

    因此,从完全正确的解决方案来看,正则表达式中的这些部分遭受了灾难性的回溯:

    (?:.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*
    (?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?.)+
    

    由于.可以匹配任何字符,因此上面的片段会退化为典型的灾难性回溯模式(A*)*。通过将正则表达式的权力降低到其严格的子集,您可以更清楚地看到问题:

    (?:a[a]+)*
    (?:[a](?:[a]*[a])?a)+
    

这是使用RegExp文字的解决方案,它与问题中字符串文字中指定的相同。你正确地完成了RegExp文字的转义,但是在RegExp构造函数中使用它:

var r = /[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])/i;

至于等效的RegExp构造函数解决方案:

var r = new RegExp("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])", "i");

答案 1 :(得分:1)

不完全是您问题的答案,但您首先需要做的是减少必须使用&#34;更正&#34;来测试的文本部分的数量。图案。在您的html示例文件中,您有大约3300个文本字符串要使用正则表达式进行测试。请记住,使用正则表达式会产生成本,因此删除无用的文本部分是一个优先事项:

var textParts = document.body.textContent
               .split(/\s+/) // see the note
               .filter(function(part) {
                   return part.length > 4 && part.length < 255 && part.indexOf('@') > 1; 
               });

alert(textParts.join("\n"));

现在你只有大约50个文本部分需要测试。

注意:如果您想接收双引号内有空格的帐户电子邮件地址,可以尝试更改:

.split(/\s+/)

.split(/(?=[\s"])((?:"[^"\n\\]*(?:\\.[^"\n\\]*)*"[^"\s]*)*)(?:\s+|$)/)

(不作任何保证)

关于你的模式:你的模式中的错误已经被其他答案和评论所指出,但请注意,你可以用这个更快地获得相同的结果(相同的匹配):

/\b\w[!#-'*+\/-9=?^-~-]*(?:\.[!#-'*+\/-9=?^-~-]+)*@[a-z0-9]+(?:-[a-z0-9]+)*\.[a-z0-9]+(?:[-.][a-z0-9]+)*\b/i

答案 2 :(得分:0)

这是一个不太严格的正则表达式的例子,速度很快。

ALTER TABLE user_data
    PARTITION (name = 'ABC')
    SET LOCATION = 'db/partitions/new';
function getEmails(str) {
  var r = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b/ig;
  var emails = [];
  var e = null;
  var n = 0;
  while ((e = r.exec(str)) !== null) {
    emails[n++] = e[0];
  }
  return emails;
}

function emailTest() {
   var str = document.getElementsByTagName('body')[0].innerHTML;
   var emails = getEmails(str);
   document.getElementById('found').innerHTML=emails.join("\n");
}

emailTest();
  
#found {
  color:green;
  font-weight:bold;
}