Java RegEx Group StackOverflow

时间:2014-01-05 12:18:31

标签: java regex

我目前正在尝试使用RegEx解析Java中的一些HTML。在实时代码的较小测试样本上它可以工作,但是在对实时代码进行尝试时,正则表达式引擎会破坏堆栈。

以下是我正在使用的代码和RegEx。

/**
 *  RegEx Explanation:  
 *      "(?i)" - Turn on case insensitive mode
 *      "<BR><BR><B>.+?</B><BR>" - Match the format for a group name
 *      "(?-i)" - Turn off case insensitive mode
 *      "(.|\\r|\\n)" - Match all the text following the group name incl. newlines 
 *      "(?=((?i)<BR><BR><B>.+?</B><BR>(?-i))" - and lookahead for the start of a new group, make the match lazy and use case-insensitive mode
 *      "+?)" - Make the lookahead lazy, close out the capture group.
 */
Pattern filterPattern = 
   Pattern.compile("(?i)(<BR><BR><B>.+?</B><BR>)(?-i)(.|\\r|\\n)+?(?=((?i)<BR><BR><B>.+?</B><BR>(?-i))+?)");
   Matcher match = filterPattern.matcher(content);

   ArrayList<String> groups = new ArrayList<String>();
   // Retrieve the matches found by the RegEx
   while(match.find()) {
     if(match.groupCount() > -1) {
        groups.add(match.group(0));
     }
   }

实时html是一个电路板列表(http://menu.2ch.net/bbsmenu.html),但一般格式为:

<br><br><b>Group name</b><br>
<a href="board url">Name of the board</a><br>

使用不同数量的链接重复多次。我避免使用像JSoup这样的常规HTML解析器,因为格式是一致的,并且在第一遍中使用RegEx更容易定位以提取部分。

当我调用group()时发生堆栈溢出。其他问题表明这是由于Java中的group()调用没有对递归深度的限制,因此它将一直运行直到达到堆栈限制。我不太擅长RegEx,这可能就是为什么我错过了一个可能更容易表达的原因。我怀疑递归问题是在交替时发生的(。| \ r | \ n),但由于组太多,它可能很容易发生。我不知道。

是否有更好的表达方式来避免灾难性的复发?

1 个答案:

答案 0 :(得分:2)

正如他们在评论中所说,使用解析器,您可以通过XPath或类似方式访问DOM!

为了帮助您使用正则表达式,请考虑(这些都没有经过测试,仅来自内存):

(?is)(?:<BR><BR><B>(.+?)</B><BR>)(.*?)(?=<BR><BR><B>.+?</B><BR>)

(?i)(?:<BR><BR><B>(.+?)</B><BR>)\s*((?:<A HREF=.*?>.*?</A><BR>\s*)+)
  • ((?i)blah(?-i))很难阅读,请改用(?i:blah),这就是它的设计方式,或只使用一个(?i),因为您不希望任何特定的区分大小写正确的正则表达式
  • 如果您启用DOTALL模式,则可以撰写.*?,并且它也会匹配"hello\n\r\tworld"
  • 关于(.|\\r|\\n)+?和前瞻:你不需要重复下一个标题,你只是在寻找下一个的存在
  • 如果您使用非捕获组,则可以使用group(1)group(2)分别查找标题和链接:(?:I'm not a numbered group)
  • 如果格式一致,您可以表达它而不是使用(.|\\r|\\n)+?<A HREF=(.*?)>(.*?)</A><br>\n
  • 我给出的第一个选项可能会在最后一个类别中打破,但我认为你也是如此,因为你正在使用+?,也许是(?=...)?使其成为可选匹配,但我我不确定它会起作用。使用第二个选项,更重要的是!