我正在使用node.js dom-parser,该分析器(不理想地)使用正则表达式将标签从DOM中拉出。
您可以在以下位置找到dom-parser: https://github.com/ershov-konst/dom-parser
有时,某些网页的HTML(例如https://www.ecosia.org/)会导致node.js应用程序挂起。我已经使用普通的香草匹配脚本进行了测试,发现tagRegExp导致脚本挂起(也许是由于灾难性的回溯?)
我实际上是用它来查找链接rel =“ canonical”和href =“ xyz”(如果有的话,ecosia则没有规范)。
tagRegExp:
/(<\/?[a-z][a-z0-9]*(?::[a-z][a-z0-9]*)?\s*(?:\s+[a-z0-9-_]+=(?:(?:'[\s\S]*?')|(?:"[\s\S]*?")))*\s*\/?>)|([^<]|<(?![a-z\/]))*/gi
纯JS测试脚本:
<script type="text/javascript">
var text = '... html source ...';
var text_esc = text
text_esc = text_esc.replace(/\</g, "<");
text_esc = text_esc.replace(/\>/g, ">");
var regex = /(<\/?[a-z][a-z0-9]*(?::[a-z][a-z0-9]*)?\s*(?:\s+[a-z0-9-_]+=(?:(?:'[\s\S]*?')|(?:"[\s\S]*?")))*\s*\/?>)|([^<]|<(?![a-z\/]))*/gi;
var found = text.match(regex);
var found_len = found.length;
document.write("Text: " + text_esc + "<br /><br />" + "Regex pattern: " + regex + "<br /><br />");
document.write("Matches: " + found_len + "<br /><br />");
for (var i=0;i<found_len;i++)
{
found[i] = found[i].replace(/\</g, "<");
found[i] = found[i].replace(/\>/g, ">");
document.write("[" + i + "]: " + found[i] + "<br /><br />");
}
</script>
任何想法都值得欢迎。预先感谢。
答案 0 :(得分:1)
问题是由[\s\S]*?
模式和效率低下的(x|[^x])*
类似模式引起的。
您可以使用
/(<\/?[a-z][a-z0-9]*(?::[a-z][a-z0-9]*)?\s*(?:\s+[a-z0-9-_]+=(?:'[^']*'|"[^"]*"))*\s*\/?>)|[^<]*(?:<(?![a-z\/])[^<]*)*/gi
'[\s\S]*?'
变成'[^']*'
,其中[^']*
是一个贪婪量化的否定字符类,与除'
以外的任何字符相匹配,而"[\s\S]*?"
在一样的方法。否定的字符类比.*?
懒惰的字符类要好,因为它可以一次性匹配除指定字符之外的所有字符,并且正则表达式引擎不必在此模式之后尝试所有后续子模式,然后展开每个子模式失败后的时间。
([^<]|<(?![a-z\/]))*
可以和[^<]*(?:<(?![a-z\/])[^<]*)*
一样unrolled,它将匹配相同的文本,但是速度更快(与以前一样,带有贪婪的量词的否定字符类模式将更快地通过文本)
请注意,我还删除了几个冗余的非捕获组。