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

Java正则表达式将HTML列表转换为文本,java,html,xml,regex,Java,Html,Xml,Regex,我有以下表格中的数据: <ol> <li>example1</li> <li>example2</li> <li>example3</li> </ol> 磅符号必须与ol html标记相关联。我正在使用java正则表达式,到目前为止,我已经做到了: info = info.replaceAll("(?s).<ol>\n(<li>(.*?)</li>\n)*<

我有以下表格中的数据:

<ol>
<li>example1</li>
<li>example2</li>
<li>example3</li>
</ol>
磅符号必须与ol html标记相关联。我正在使用java正则表达式,到目前为止,我已经做到了:

info = info.replaceAll("(?s).<ol>\n(<li>(.*?)</li>\n)*</ol>","# $2");
缺少示例2和示例1


关于我做错了什么有什么想法吗?

编辑:修复hoipolloi提到的具有前瞻性的
问题:

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

这一个对您的示例有效:

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

    编辑:添加解释。(也许有人会推翻他们的否决票。)

  • (?:\s*)?
    • 如果它存在,则匹配
      以及它后面的任何空格。
      (?:
      表示不捕获此组
  • (.*)
  • 
    
    • 匹配
    • 任何内容
    • 。并在第一组中捕获
      任何内容
      *?
      表示不贪婪地匹配任何长度(即在
    • 之后匹配第一个
  • 新条款
    (?=((?!)(.\n))*)
    • 确保
  • (?:\s*)?
    • 并匹配任何尾随空格加上

  • “您做错了什么”的答案是,您正在用第二组的值替换整个单个正则表达式(从ol一直匹配到/ol)。第二组是重复的片段,因此,
    $2
    的结果是该组的最后一个匹配。您的正则表达式有几个问题:

    • 它在捕获组中包含一个捕获组
    • 总的来说,它只会匹配一次(它包括一个开始——其中只有一个)
    我建议的解决方案是:不要把自己绑在结上。用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();
    
    Pattern p=Pattern.compile((*?);
    匹配器m=p.Matcher(“…”);
    StringBuffer sb=新的StringBuffer();
    while(m.find()){
    附加(m.group(1))。附加(“\n”);
    }
    字符串结果=sb.toString();
    
    我认为您可以使用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);
        }
    }
    
    import java.io.ByteArrayInputStream;
    导入javax.xml.parsers.DocumentBuilder;
    导入javax.xml.parsers.DocumentBuilderFactory;
    导入javax.xml.xpath.xpath;
    导入javax.xml.xpath.XPathConstants;
    导入javax.xml.xpath.XPathExpression;
    导入javax.xml.xpath.XPathFactory;
    导入org.w3c.dom.Document;
    导入org.w3c.dom.Node;
    导入org.w3c.dom.NodeList;
    公开课Foo{
    公共静态void main(字符串[]args)引发异常{
    最终字符串信息=“\n\n
  • 示例1
  • \n
  • 示例2
  • \n
  • 示例3
  • \n\n\n”; 最终文件=解析文件(信息); final XPathExpression XPathExpression=getXPathExpression(“//ol/li”); 最终节点列表节点=(节点列表)xPathExpression.evaluate(文档,XPathConstants.NODESET); //打印#示例1\n#示例2\n#示例3 对于(int i=0;i
    我会使用更简单的解决方案,而不是复杂的正则表达式。例如:

        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$
        }
    
    Scanner scann=new Scanner(str);//参数可以是文件或输入流
    scann.useDelimiter(“”);
    while(scann.hasNext())
    {
    str=scann.next();
    str=str.replaceAll(“
  • (.*)
  • \n*”,“#$1”+ “\n”);//$NON-NLS-1$//$NON-NLS-2$ }
    不要使用正则表达式解析XML/HTML。句号。你永远不会处理输入中可能合法出现的所有变化,你将永远告诉提供内容的人你很抱歉,你只能处理XML/HTML的一个受限子集,他们将永远诅咒你。如果你真的这样做了当您可以处理99%的合法输入时,您的代码将无法维护且速度缓慢

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

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

    (?:|\G)
    确保每一组匹配要么从
    开始,要么从上次匹配结束的地方开始,因此它永远无法在
    元素内开始匹配。

    这里有许多相关问题的示例。@Nightfirecat-尽管在本例中通常对html和正则表达式进行声明,但它会看到我完全合理。好吧,假设它的格式都正确,它是完全可能的(甚至有些合理),但这仍然不是RegEx的本意。同意,但如果你采用Neil的方法,这是情有可原的。我得说,这很聪明。+1解决这个问题的推理。另一方面,除非代码是虐待狂社会竞赛的参赛作品
        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$
        }
    
    info = info.replaceAll("(?:<ol>|\\G)\\s*<li>(.+?)</li>(?:\\s*</ol>)?",
                           "# $1\n");