鉴于以下内容:
> 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();
}
答案 0 :(得分:2)
我会使用一个简单的perl脚本来编程。
算法如下:您跟踪前一行(nprev
上的嵌套级别,开头为0)并计算当前行(ncur
)中的嵌套级别。迭代这些行,每次迭代都有三个选项:
nprev
== ncur
,然后关闭</li>
代码(此处您已打开一个代码),打开{{1} }表示当前行元素,并将当前行的值打印到输出。
<li>
&lt; nprev
即可。这意味着您处于打开的ncur
标记(或全局范围)中,并打印上一行(父值)上的值。因此,您应该打开<li>
和<ul>
代码并在当前行上打印值。
<li>
&gt; nprev
即可。启动一个小的内循环,将ncur
减1,直到它等于nprev
。每次必须降低值时,请关闭ncur
和</li>
标记。 完成循环后,打开另一个</ul>
标记,在当前行打印值并继续外循环。
当您迭代所有行时,假设输入末尾有一条虚假行,<li>
等于0.再次启动步骤3,斜体部分除外。澄清一下:如果不满足第3步的条件(ncur
)(输入不包含任何行的情况),则不执行任何操作。
你已经完成了。
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;
}
}