Java正则表达式启用除已封闭标记之外的文本内的链接

时间:2017-03-16 22:23:34

标签: java html regex parsing html-parsing

假设用户输入文本包含HTML和链接,我想启用链接,并使already_tag_closed网址保持不变。

(我知道有很多正则表达式的url模式问题,但我找不到这个解决方案)

例如:

String urlRegex = "((https?|ftp|gopher|telnet|file):((//)|(\\\\))+[\\w\\d:#@%/;$()~_?\\+-=\\\\\\.&]*)";
Pattern urlPattern = Pattern.compile(urlRegex, Pattern.CASE_INSENSITIVE);

String s = ...
urlPattern.matcher(s).replaceAll("<a href='$0' target='_blank'>$0</a>")

它可以将"google https://google.com"翻译为google <a href='https://google.com' target='_blank'>https://google.com</a>,好。

但如果字符串是

"<a href=\"http://www.google.com/\">google</a> " +
" http://www.google.com/  " +
" <a href=\"https://facebook.com/\">facebook</a> " +
" https://facebook.com ";

它将成为

<a href="<a href='http://www.google.com/' target='_blank'>http://www.google.com/</a>">google</a>  <a href='http://www.google.com/' target='_blank'>http://www.google.com/</a>   <a href="<a href='https://facebook.to/' target='_blank'>https://facebook.to/</a>">facebook</a>  <a href='https://facebook.com' target='_blank'>https://facebook.com</a> 

它不应该触及href中的值,因此我将urlRegex更改为:

urlRegexExceptAnchor = "(?<!\\<a\\ href=\")(http|https):\\/\\/[^ ]*"; 

好吧,它可以处理与锚标签混合的文本。

,如果文字包含iframe,则会再次失败:

<iframe src="https://www.facebook.com/plugins/post.php?href=https%3A%2F%2Fwww.facebook.com%2Fnytimes%2Fposts%2F10151112309519999&width=500" width="500" height="525" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowTransparency="true"></iframe>

成为

<iframe src="<a href='https://www.facebook.com/plugins/post.php?href=https%3A%2F%2Fwww.facebook.com%2Fnytimes%2Fposts%2F10151112309519999&width=500"' target='_blank'>https://www.facebook.com/plugins/post.php?href=https%3A%2F%2Fwww.facebook.com%2Fnytimes%2Fposts%2F10151112309519999&width=500"</a> width="500" height="525" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowTransparency="true"></iframe>

再次无效。

我想我会面临越来越多的情况,因为There are a lot of tags that accepts URLs。我无法逃脱aiframe代码......

该文字由用户输入,我确定可以过滤掉一些无效标记,例如formheadinput ...,但仍有很多标记处理...(甚至内联css背景网址)

我现在能想到的是使用类似JSoup的内容将整个文本传输到html doc,然后逐个处理textNode。但我认为这太过分了。 (每个页面显示将调用JSoup ...)

有没有更简单的方法来实现这一目标?

1 个答案:

答案 0 :(得分:0)

对于遇到类似问题的人,这是我的JSoup解决方案:

  private static void processNode(Node node) {
    if (node instanceof TextNode) {

      Node parent = node.parent();
      if (parent != null && (StringUtils.equalsAnyIgnoreCase(parent.nodeName(),
        "a", "iframe", "embed" , "img" , "object" , "script" , "video" , "applet"))) {
        logger.debug("parent = {} , skipped", parent.nodeName());
      }
      else {
        TextNode textNode = (TextNode) node;

        String text = textNode.text();
        text = urlPattern.matcher(text).replaceAll("<a href='$0' target='_blank'>$0</a>");

        TextNode r = new TextNode(text , null);
        node.replaceWith(r);
      }
    } else if (node instanceof Element) {
      Element ele = (Element) node;
      for (Node childNode : ele.childNodes()) {
        processNode(childNode);
      }
    }
  }

工作正常......(暂时)