逃避HTML标记中的灾难性回溯

时间:2017-03-29 00:17:39

标签: javascript regex parsing html-parsing

就像我在标题中所说的那样,我的数据集是标记,看起来有点像这样

<!DOCTYPE html>
<html>
<head>
    <title>page</title>
</head>
<body>
<main>

<div class="menu">
    <img src=mmayboy.jpg>
    <p> stackoverflow is good </p>
</div>

<div class="combine">
    <p> i have suffered <span>7</span></p>
</div>
</main>
</body>
</html> 

我的正则表达式引擎尝试分别匹配以下每个节点块,即我可以尝试匹配combinemenu。在一次拍摄中,这就是我的正则表达式引擎的样子,虽然我潜入其正下方的内部。

/(<div class="menu">(\s+.*)+<\/div>(?:(?=(\s+<div))))/

它试图深入到该标记并抓取所需的节点块。就这些。至于内部,我们在这里

/
(
 <div class="menu"> // match text that begins with these literals
  (
   \s+.*
  )+ /* match any white space or character after previous. But the problem is that this matches up till the closing tag of other DIVs i.e greedy. */
  <\/div> // stop at the next closing DIV (this catches the last DIV)
  (?: // begin non-capturing group 
   (?=
    (
     \s+<div
     ) /* I'm using the positive lookahead to make sure previous match is not followed by a space and a new DIV tag. This is where the catastrophic backtracking is raised. */
   )
  )
 )
/

我已经通过评论缩进它,以帮助任何愿意提供帮助的人。我也从博客和the manual 中寻找解决方案,他们说它是由具有太多可能性的表达引起的,并且可以通过降低结果的可能性来补救,{{1而不是+?而不是我试过的那么难,我无法将其中的任何一个应用到我当前的困境中。

1 个答案:

答案 0 :(得分:1)

(\s+.*)+

可能简化为

[^]*?

这应该可以防止灾难性的回溯。整体简化:

/<div class="menu">[^]*?<\/div>/

您是否考虑使用an HTML parser代替?

var parser = new DOMParser();
var doc = parser.parseFromString(data, 'text/html');
var menu = doc.getElementsByClassName('menu')[0];

console.log(menu.innerHTML);