递归文本转换

时间:2009-09-05 17:06:41

标签: java algorithm xhtml

鉴于以下内容:

  > This is level 1
  > This is level 2
  >> This is level 2.1
  >> This is level 2.2
  >>> This is level 2.2.1
  >>> This is level 2.2.2
  > This is level 3

如果没有像ANTLR这样的解析器库,您如何将该文本转换为XHTML?那就是:

  <ul>
  <li>This is level 1</li>
  <li>This is level 2
    <ul>
    <li>This is level 2.1</li>
    <li>This is level 2.2
      <ul>
      <li>This is level 2.2.1</li>
      <li>This is level 2.2.2</li>
      </ul>
    </li>
    </ul>
  </li>
  <li>This is level 3</li>
  </ul>

我尝试了递归和迭代算法。令人不安的部分是将ul标签从深度3(2.2.2)关闭到深度1(3)。

解决方案

以下代码解决了这个问题。当每个级别代表一个数字而不是一行文本时,标记为正确的解决方案是正确的。输出中的新行是为了人类的可读性,但由于(X)HTML是计算机读取的,因此它们已从下面的代码中删除。

public String transform( String source ) {
  // Level 0 means no >, level 1 for one >, etc.
  //
  int currentLevel = 0;
  int nextLevel = 0;

  StringBuilder sb = new StringBuilder( 512 );

  // Split source on newlines.
  //
  String[] lines = source.split( "\\r?\\n" );

  for( String line: lines ) {
    int indents = line.lastIndexOf( ">" );

    if( indents < 0 ) {
      continue;
    }

    String content = line.substring( indents + 1 ).trim();

    nextLevel = indents + 1;

    if( nextLevel == currentLevel ) {
      sb.append( "</li><li>" );
    }
    else if( nextLevel > currentLevel ) {
      sb.append( "<ul><li>" );
    }
    else if( nextLevel < currentLevel ) {
      for( int i = 0; i < currentLevel - nextLevel; i++ ) {
        sb.append( "</li></ul>" );
      }
      sb.append( "</li><li>" );
    }

    sb.append( content );

    currentLevel = nextLevel;
  }

  // Close the remaining levels.
  //
  for( int i = 0; i < currentLevel; i++ ) {
    sb.append( "</li></ul>" );
  }

  return sb.toString();
}

3 个答案:

答案 0 :(得分:2)

我会使用一个简单的perl脚本来编程。

算法如下:您跟踪前一行(nprev上的嵌套级别,开头为0)并计算当前行(ncur)中的嵌套级别。迭代这些行,每次迭代都有三个选项:

  1. nprev == ncur ,然后关闭</li>代码(此处您已打开一个代码),打开{{1} }表示当前行元素,并将当前行的值打印到输出。

  2. <li>&lt; nprev 即可。这意味着您处于打开的ncur标记(或全局范围)中,并打印上一行(父值)上的值。因此,您应该打开<li><ul>代码并在当前行上打印值。

  3. <li>&gt; nprev 即可。启动一个小的内循环,将ncur减1,直到它等于nprev。每次必须降低值时,请关闭ncur</li>标记。 完成循环后,打开另一个</ul>标记,在当前行打印值并继续外循环。

  4. 当您迭代所有行时,假设输入末尾有一条虚假行,<li>等于0.再次启动步骤3,斜体部分除外。澄清一下:如果不满足第3步的条件(ncur)(输入不包含任何行的情况),则不执行任何操作。

  5. 你已经完成了。

    P.S。解析和转换文本是一项繁琐的任务,当您尝试将其作为最大限度地使用时,它会变得很有趣。

答案 1 :(得分:2)

以下是基于Pavel算法的示例实现

class listCreator {

    public String createList(String source) {
        int currentLevel = 0; //Level 0 means beginning, level 1 means a single > was present and so on
        int nextLevel = 0;
        StringBuilder sb = new StringBuilder();
        //Assumes source is to be split on newlines
        String[] tmp = source.split("\n");
        for (String t: tmp) {
            //Needs validation, if source is not what we expect it'll blow up...
            //We are expecting a number of > followed by a space
            String[] levelContent = t.split(" ");
            nextLevel = levelContent[0].lastIndexOf(">") + 1;

            if (nextLevel == currentLevel) {
                sb.append("</li>\n<li>");
                sb.append(levelContent[1]);
            } else if (nextLevel > currentLevel) {
                sb.append("<ul>\n<li>");
                sb.append(levelContent[1]);
            } else if (nextLevel < currentLevel) {
                for (int i = 0; i < currentLevel-nextLevel; i++) {
                    sb.append("</li>\n</ul>\n");
                }
                sb.append("</li>\n<li>");
                sb.append(levelContent[1]);
            }

            currentLevel = nextLevel;
        }
        //Close up remaining levels
        for (int i=0; i < currentLevel; i++) {
            sb.append("</li>\n</ul>\n");
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        String source1 = "> 1\n> 2\n>> 2.1\n>> 2.2\n>>> 2.2.1\n>>> 2.2.2\n> 3\n";
        String source2 = "> 1\n> 2\n>> 2.1\n>> 2.0.1\n>>> 2.0.1.2\n>> 2.2\n>>> 2.2.1\n>>> 2.2.2\n> 3\n";
        listCreator lc = new listCreator();
        System.out.println(lc.createList(source1));
        System.out.println(lc.createList(source2));
    }

}

答案 2 :(得分:-1)

试试这个,没有时间测试它,但应该工作。另外一个请求,我是一个菜鸟,有人可以指点我在这里教一个如何格式化答案的资源。

yourFunction() {
    //Split text into lines
    String[] lines = text.split("\n");

    System.out.println("<ul>");
    getHTML(lines, 0, 1);
    System.out.println("</ul>");
}

getHTML(String[] lines, int index, int level) {
    int thisLevel = (lines[index].lastIndexOf(">") + 1);

    if(thisLevel == level) {
        System.out.println("<li>" + lines[index].replaceAll(">", "").trim() + "</li>");
        getHTML(lines, (index + 1), thisLevel);
        return;
    } else if(thisLevel > level) {
        System.out.println("<ul>");
        System.out.println("<li>" + lines[index].replaceAll(">", "").trim() + "</li>");
        getHTML(lines, (index + 1), thisLevel);
        return;
    } else if(thisLevel < level) {
        System.out.println("/<ul>");
        System.out.println("<li>" + lines[index].replaceAll(">", "").trim() + "</li>");
        getHTML(lines, (index + 1), thisLevel);
        return;
    }
}