Java正则表达式将HTML列表转换为文本

时间:2011-07-13 22:44:15

标签: java html xml regex

我的表格中有数据:

<ol>
<li>example1</li>
<li>example2</li>
<li>example3</li>
</ol>

需要变成

# example1
# example2
# example3

井号必须与ol html标签相关联。我正在使用java正则表达式,这是我到目前为止所做的:

info = info.replaceAll("(?s).<ol>\n(<li>(.*?)</li>\n)*</ol>","# $2");

info是包含数据的字符串对象。 li标签之间也可能有换行符。当我运行它时,它只打印最后一个项目。即结果是

 # example3

example2和example1缺失

对我做错了什么的想法?

7 个答案:

答案 0 :(得分:1)

你的正则表达式有几个问题:

  • 它包含捕获组内的捕获组
  • 总体而言,它只会匹配一次(它包括一个开头 - 只有其中一个。

我建议的解决方案:不要束缚自己。用Matcher.find()编写一个循环,逐个拉出匹配并将它们添加到字符串缓冲区。它会是这样的:

    Pattern p = Pattern.compile("<ol>(.*?)</ol>");
    Matcher m = p.matcher("...");
    StringBuffer sb = new StringBuffer();
    while (m.find()) {
        sb.append("#").append(m.group(1)).append("\n");
    }
    String result = sb.toString();

答案 1 :(得分:1)

我认为你可以使用XPath和Java的文档解析器实现更强大的解决方案,如下所示:

import java.io.ByteArrayInputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class Foo {

    public static void main(String[] args) throws Exception {
        final String info = "<html>\n<body>\n<ol>\n<li>example1</li>\n<li>exmaple2</li>\n<li>example3</li>\n</ol>\n</body>\n</html>";
        final Document document = parseDocument(info);
        final XPathExpression xPathExpression = getXPathExpression("//ol/li");
        final NodeList nodes = (NodeList) xPathExpression.evaluate(document, XPathConstants.NODESET);

        // Prints # example1\n# exmaple2\n# example3
        for (int i = 0; i < nodes.getLength(); i++) {
            final Node liNode = nodes.item(i);
            if (liNode.hasChildNodes()) {
                System.out.println("# " + liNode.getChildNodes().item(0).getTextContent());
            }
        }
    }

    private static Document parseDocument(final String info) throws Exception {
        final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        final DocumentBuilder builder = factory.newDocumentBuilder();
        return builder.parse(new ByteArrayInputStream(info.getBytes("UTF-8")));
    }

    private static XPathExpression getXPathExpression(final String expression) throws Exception {
        final XPathFactory factory = XPathFactory.newInstance();
        final XPath xpath = factory.newXPath();
        return xpath.compile(expression);
    }
}

答案 2 :(得分:0)

编辑:修复hoipolloi提到的<ul>问题并展望未来:

(?=((?!</ul>)(.|\n))*</ol>)

这个就是你的例子:

info.replaceAll(
    "(?:<ol>\s*)?<li>(.*?)</li>(?=((?!</ul>)(.|\n))*</ol>)(?:\s*</ol>)?",
    "# $1"
);

修改:添加说明。 (也许有人会改掉他们的投票。)

  1. (?:<ol>\s*)?
    • 如果存在,请匹配<ol>以及其后的任何空格。 (?:表示不捕获此组。
  2. <li>(.*?)</li>
    • 匹配<li>anything</li>。并捕获第一组中的anything*?表示非贪婪地匹配任何长度(即匹配</li>之后的第一个<li>。)
  3. 新条款 (?=((?!</ul>)(.|\n))*</ol>)
    • 确保在</ol>
    • 之前<li>跟随此</ul>
  4. (?:\s*</ol>)?
    • 并匹配任何尾随空格加上</ol>

答案 3 :(得分:0)

“你做错了什么”的答案是你要用值单个正则表达式(从ol一直到/ ol匹配) >你的第二组。第二组是重复片段,因此$2的结果是该组的最后一场比赛。

答案 4 :(得分:0)

我会使用更简单的解决方案而不是复杂的正则表达式。例如:

    Scanner scann= new Scanner(str); //the parameter can be a file or an inputstream 
    scann.useDelimiter("</?ol>");
    while (scann.hasNext())
    {
        str = scann.next();
        str = str.replaceAll("<li>(.*?)</li>\n*","# $1" +
                "\n"); //$NON-NLS-1$ //$NON-NLS-2$
    }

答案 5 :(得分:0)

不要使用正则表达式来解析XML / HTML。完全停止。您永远不会处理输入中可能合法发生的所有可能变化,并且您将永远告诉提供您抱歉的内容的人,您只能处理XML的受限子集/ HTML,他们将永远诅咒你。如果你达到了可以处理99%合法输入的程度,那么你的代码将无法维持且速度慢。

有现成的解析器来完成这项工作 - 使用它们。

答案 6 :(得分:0)

info = info.replaceAll("(?:<ol>|\\G)\\s*<li>(.+?)</li>(?:\\s*</ol>)?",
                       "# $1\n");

(?:<ol>|\G)确保每一对匹配 <ol>元素内。