如何使用 Java 或 Javascript 将 ASCII Art 解析为 HTML? [关闭]
Posted
技术标签:
【中文标题】如何使用 Java 或 Javascript 将 ASCII Art 解析为 HTML? [关闭]【英文标题】:How can I parse ASCII Art to HTML using Java or Javascript? [closed] 【发布时间】:2013-09-09 08:49:15 【问题描述】:我看到 Neo4j API 通过其 API 非常巧妙地使用了 ASCII Art:
http://jaxenter.com/getting-started-with-neo4j-the-java-graph-database-47955.html
我想尝试类似的东西,但使用 ASCI Art to HTML。如何解析 ASCII 艺术,例如,给定一个 ASCII 艺术输入,例如:
--------------------------------
I I
I ------- ------- I
I I I I I I
I I A I I B I I
I I I I I I
I ------- ------- I
I I
I I
--------------------------------
:可能会导致 HTML 输出类似于:
<div>
<div style='display:inline;'>
A
</div>
<div style='display:inline;'>
B
</div>
</div>
更新
问题已结束,理由是我需要“对正在解决的问题表现出最低限度的理解。”。我确实对要解决的问题有所了解。问题是我要解决的问题是使模板化的 HTML 在以下 Web 框架的源代码中更易于理解:
https://github.com/zubairq/coils
:尽管该解决方案可以应用于任何 Web 框架。从那以后,我看到有人尝试在这里用 C++ 制作初始版本:
https://github.com/h3nr1x/asciidivs2html/blob/master/asciidivs2html.cpp
:非常令人印象深刻!如果您可以让它在 Java 或 Clojure 中工作,那么如果我们可以重新提出问题,我将提名赏金,这样您就可以获得更多积分:)
我运行了@meewok 提供的Java 解决方案,结果如下:
$ java AsciiToDIVs.RunConverter
Created a box(ID=0,X=0,Y=0,width=33,height=10)
Created a box(ID=1,X=2,Y=4,width=8,height=5,parent=0)
Created a char(Char=A,X=4,Y=7,parent=1)
Created a box(ID=2,X=2,Y=21,width=8,height=5,parent=0)
Created a char(Char=B,X=4,Y=24,parent=2)
<div><div><div>A</div></div><div><div>B</div></div></div>
【问题讨论】:
为什么是最后一票?我想在一个可以返回 HTML 的程序中有一些 Ascii Art 这听起来很有趣 是的,听起来很有趣,但是如果一个新手要求代码或库推荐,Q 就关闭了,不是吗? 您不需要使用解析,使用填充来标记 div 的区域,提取 div 坐标,检查边框以获取封闭的父 div,然后使用此信息构建树,递归打印html标签的树。今天报告生病了=(,所以我利用我的休息时间为此编写了一个程序,请查看github.com/h3nr1x/asciidivs2html “最低限度的理解”关闭原因可能是因为您没有展示任何实际尝试自己解决这个问题。你是在要求别人为你写整件事吗? 【参考方案1】:假设您已经生成了 ASCII 艺术。
在 HTML 中,您需要做两件事。
-
将字体设置为等距字体。
将 ASCII 解析为 HTML 代码。例如
<space> to &nbsp; line break to <br/> etc
http://jsfiddle.net/kenthaha/9rCXP/
希望它成功。
【讨论】:
在 jsfiddle 中,输出是 ascii 艺术。如何使用 ascii 艺术从 ascii 艺术生成 html 请注意,如果这个是的问题,答案就是style="font-family: monospace; white-space: pre"
,或者更简单,“把它放在<pre>
标签中”
@eric 你的意思是 ASCII 艺术输出可能与输入相同,因此用户可以浏览 ASCII 艺术网站吗?实际上听起来很有趣……有点像保罗谈到的网络黑客。这是你的意思吗?
Kenneth — 恐怕你误解了这个问题。 @Zubair 想要的是能够将任意布局的 ASCII 艺术表示传递给一些将生成相应 HTML 容器元素的代码。【参考方案2】:
方法
实施的解决方案如下:
在内存中创建一个类似于棋盘的二维数组(数组的数组)。然后我将创建一个算法,当它检测到“-”字符时,我会初始化一个方法来检测字符后面的剩余角(右上角、左下角、右下角)及其结束位置。
示例(快速伪代码):
while(selectedCell==I)
selectedCell=selectedCell.goDown();
使用这样的策略,您可以绘制出您的盒子以及哪些盒子包含在其中。
剩下的就是将此信息打印为 html..
快速而肮脏的实现
因为我有这种心情,所以我花了一个多小时来快速制作一个玩具实现。 下面是非优化的,因为我不使用迭代器来遍历单元格,并且需要重构才能成为一个严肃的框架。
Cell.java
package AsciiToDIVs;
public class Cell
public char Character;
public CellGrid parentGrid;
private int rowIndex;
private int colIndex;
public Cell(char Character, CellGrid parent, int rowIndex, int colIndex)
this.Character = Character;
this.parentGrid = parent;
this.rowIndex = rowIndex;
this.colIndex = colIndex;
public int getRowIndex()
return rowIndex;
public int getColIndex()
return colIndex;
CellGrid.java
package AsciiToDIVs;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Iterator;
public class CellGrid
private ArrayList<ArrayList<Cell>> CellGridData;
public CellGrid(String asciiFile) throws IOException
readDataFile(asciiFile);
public ArrayList<FoundObject> findBoxes(FoundBoxObject parent)
int startRowIndex = 0, startColIndex = 0,
parentRowLimit = Integer.MAX_VALUE,
parentColLimit = Integer.MAX_VALUE,
startingColIndex = 0;
if(parent != null)
startRowIndex = parent.getRowIndex()+1;
startColIndex = startingColIndex = parent.getColIndex()+1;
parentRowLimit = parent.getRowIndex() + parent.getHeight();
parentColLimit = parent.getColIndex() + parent.getWidth();
ArrayList<FoundObject> results = new ArrayList<FoundObject>();
Cell currentCell;
if(startRowIndex>=CellGridData.size())
return null;
for(; startRowIndex<CellGridData.size() && startRowIndex<parentRowLimit; startRowIndex++ )
startColIndex = startingColIndex;
for(; startColIndex< CellGridData.get(startRowIndex).size() && startColIndex<parentColLimit; startColIndex++)
FoundBoxObject withinBox = checkWithinFoundBoxObject(results, startRowIndex, startColIndex);
if(withinBox !=null)
startColIndex+=withinBox.getWidth();
currentCell = getCell(startRowIndex, startColIndex);
if(currentCell!=null)
if(currentCell.Character == '-') // Found a TOP-CORNER
int boxHeight = getConsecutiveIs(startRowIndex+1, startColIndex) + 1;
if(boxHeight>1)
int boxWidth = getConsecutiveDashes(startRowIndex, startColIndex);
FoundBoxObject box = new FoundBoxObject(startRowIndex, startColIndex, boxWidth, boxHeight, parent);
results.add(box);
findBoxes(box);
startColIndex+=boxWidth;
//This is a character
else if(currentCell.Character != '-' && currentCell.Character != 'I' && currentCell.Character != ' '
&& currentCell.Character != '\n' && currentCell.Character != '\n' && currentCell.Character != '\t')
FoundCharObject Char = new FoundCharObject(startRowIndex, startColIndex, parent, currentCell.Character);
results.add(Char);
if(parent!=null)
parent.containedObjects = results;
return results;
public static String printDIV(ArrayList<FoundObject> objects)
String result = "";
Iterator<FoundObject> it = objects.iterator();
FoundObject fo;
while(it.hasNext())
result+="<div>";
fo = it.next();
if(fo instanceof FoundCharObject)
FoundCharObject fc = (FoundCharObject)fo;
result+=fc.getChar();
if(fo instanceof FoundBoxObject)
FoundBoxObject fb = (FoundBoxObject)fo;
result+=printDIV(fb.containedObjects);
result+="</div>";
return result;
private FoundBoxObject checkWithinFoundBoxObject(ArrayList<FoundObject> results, int rowIndex, int colIndex)
Iterator<FoundObject> it = results.iterator();
FoundObject f;
FoundBoxObject fbox = null;
while(it.hasNext())
f = it.next();
if(f instanceof FoundBoxObject)
fbox = (FoundBoxObject) f;
if(rowIndex >= fbox.getRowIndex() && rowIndex <= fbox.getRowIndex() + fbox.getHeight())
if(colIndex >= fbox.getColIndex() && colIndex <= fbox.getColIndex() + fbox.getWidth())
return fbox;
return null;
private int getConsecutiveDashes(int startRowIndex, int startColIndex)
int counter = 0;
Cell cell = getCell(startRowIndex, startColIndex);
while( cell!=null && cell.Character =='-')
counter++;
cell = getCell(startRowIndex, startColIndex++);
return counter;
private int getConsecutiveIs(int startRowIndex, int startColIndex)
int counter = 0;
Cell cell = getCell(startRowIndex, startColIndex);
while( cell!=null && cell.Character =='I')
counter++;
cell = getCell(startRowIndex++, startColIndex);
return counter;
public Cell getCell(int rowIndex, int columnIndex)
ArrayList<Cell> row;
if(rowIndex<CellGridData.size())
row = CellGridData.get(rowIndex);
else return null;
Cell cell = null;
if(row!=null)
if(columnIndex<row.size())
cell = row.get(columnIndex);
return cell;
public Iterator<ArrayList<Cell>> getRowGridIterator(int StartRow)
Iterator<ArrayList<Cell>> itRow = CellGridData.iterator();
int CurrentRow = 0;
while (itRow.hasNext())
// Itrate to Row
if (CurrentRow++ < StartRow)
itRow.next();
return itRow;
private void readDataFile(String asciiFile) throws IOException
CellGridData = new ArrayList<ArrayList<Cell>>();
ArrayList<Cell> row;
FileInputStream fstream = new FileInputStream(asciiFile);
BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
String strLine;
// Read File Line By Line
int rowIndex = 0;
while ((strLine = br.readLine()) != null)
CellGridData.add(row = new ArrayList<Cell>());
// System.out.println (strLine);
for (int colIndex = 0; colIndex < strLine.length(); colIndex++)
row.add(new Cell(strLine.charAt(colIndex), this, rowIndex,colIndex));
// System.out.print(strLine.charAt(i));
rowIndex++;
// System.out.println();
// Close the input stream
br.close();
public String printGrid()
String result = "";
Iterator<ArrayList<Cell>> itRow = CellGridData.iterator();
Iterator<Cell> itCol;
Cell cell;
while (itRow.hasNext())
itCol = itRow.next().iterator();
while (itCol.hasNext())
cell = itCol.next();
result += cell.Character;
result += "\n";
return result;
FoundBoxObject.java
package AsciiToDIVs;
import java.util.ArrayList;
public class FoundBoxObject extends FoundObject
public ArrayList<FoundObject> containedObjects = new ArrayList<FoundObject>();
public static int boxCounter = 0;
public final int ID = boxCounter++;
public FoundBoxObject(int rowIndex, int colIndex, int width, int height, FoundBoxObject parent)
super(rowIndex, colIndex, width, height);
if(parent!=null)
System.out.println("Created a box(" +
"ID="+ID+
",X="+rowIndex+
",Y="+colIndex+
",,,parent="+parent.ID+")");
else
System.out.println("Created a box(" +
"ID="+ID+
",X="+rowIndex+
",Y="+colIndex+
",,)");
FoundCharObject.java
package AsciiToDIVs;
public class FoundCharObject extends FoundObject
private Character Char;
public FoundCharObject(int rowIndex, int colIndex,FoundBoxObject parent, char Char)
super(rowIndex, colIndex, 1, 1);
if(parent!=null)
System.out.println("Created a char(" +
"Char="+Char+
",X="+rowIndex+
",Y="+colIndex+
",parent="+parent.ID+")");
else
System.out.println("Created a char(" +
",X="+rowIndex+
",Y="+colIndex+")");
this.Char = Char;
public Character getChar()
return Char;
FoundObject.java
package AsciiToDIVs;
public class FoundObject
private int rowIndex;
private int colIndex;
private int width = 0;
private int height = 0;
public FoundObject(int rowIndex, int colIndex, int width, int height )
this.rowIndex = rowIndex;
this.colIndex = colIndex;
this.width = width;
this.height = height;
public int getRowIndex()
return rowIndex;
public int getColIndex()
return colIndex;
public int getWidth()
return width;
public int getHeight()
return height;
主要方法
public static void main(String args[])
try
CellGrid grid = new CellGrid("ascii.txt");
System.out.println(CellGrid.printDIV(grid.findBoxes(null)));
//System.out.println(grid.printGrid());
catch (IOException e)
e.printStackTrace();
更新
'printDIV' 应该是这样的(打印的 '' 比需要的多)。
public static String printDIV(ArrayList<FoundObject> objects)
String result = "";
Iterator<FoundObject> it = objects.iterator();
FoundObject fo;
while(it.hasNext())
fo = it.next();
if(fo instanceof FoundCharObject)
FoundCharObject fc = (FoundCharObject)fo;
result+=fc.getChar();
if(fo instanceof FoundBoxObject)
result+="<div>";
FoundBoxObject fb = (FoundBoxObject)fo;
result+=printDIV(fb.containedObjects);
result+="</div>";
return result;
【讨论】:
这似乎是在正确的方向 这似乎适用于我举的例子..请参阅我对问题提出的更新:) 我建议您从 .get 转换为使用迭代器来遍历 arraylist 元素。还要测试不同的情况.... 如果您想识别某些框,有时这种方法很有效。在实践中,您希望识别以有效方式捆绑在一起的一组实体。通常,这称为“解析”(字符串解析背后有大量文献)。这种方法不收集实体和真实性关系,所以我怀疑它在复杂的情况下是否会成功。 这种方法是一个玩具示例,可以识别所有遵循特定格式(遵循特定要求)的框。显然特殊情况(例如连接框)需要修改(但其他系统中的规则也是如此)。这可以扩展到处理更复杂的形状以满足简单的要求。更复杂的需求将需要更多的代码,或基于复杂算法的框架。然而,它确实充分满足了 OP 的要求,并且可以进行修改以识别其他形状,例如(三角形、连接等)。【参考方案3】:您想要的是二维解析的想法,它检测二维实体并验证它们是否具有合法关系。
见http://mmi.tudelft.nl/pub/siska/TSD%202DVisLangGrammar.pdf
困难的是定义可能的“ASCII Art”约束集。 只想认字母?仅由相同字母的字符组成? “草书”字母?盒子? (你的例子有盒子的侧面不是由相同的 ASCII 字符)。具有任意厚壁的盒子?嵌套盒子?带有(细/粗)箭头的图表?基尔罗伊在这儿吗? 蒙娜丽莎的图片中哪些字符像素提供了密度关系? “ASCII 艺术”到底是什么意思?
真正的问题是定义您打算识别的事物的范围。如果 你限制这个范围,你成功的几率就会大大增加(参见参考论文)。
这里的问题与 Java 或 javascript 没有什么特别的关系。这更相关 到算法。选择一个有限的艺术类别,选择正确的算法,然后你所拥有的是一个应该相对容易解决的编码问题。没有限制,没有算法 --> 再多的 Javascript 也能拯救你。
【讨论】:
您引用的论文没有详细说明这种解析器的工作原理。其他文献很可能更相关。本文处理基于图标关系/排列的紧急语言。另外,OP的要求并没有参考图片,所以“蒙娜丽莎的图片,其中字符像素提供密度关系?”有点夸张。 OP 确实提供了他正在寻找的示例,尽管缺少关于应该支持哪些功能集(用于识别/关系的实体)的规范(设计文档)。 OP 说,“ASCII 艺术”。这不是一个定义明确的术语。显示 1 示例几乎不构成类别的定义。您不能通过说“我想解析一些看起来像编程代码的字符串,例如 foo.bar(x,y)”来定义解析 C++ 的问题。是的,我们同意他没有定义规范。我就是这么说的,在这种情况发生之前,他无法取得任何重大进展。 是的,我想我需要更好地说明问题,我同意【参考方案4】:这是一个相当简单的 JavaScript 解决方案,通过 Node.js 测试。当然,您需要调整输入和输出方法。
var s = "\n\
--------------------------------\n\
I I\n\
I ------- ------- I\n\
I I I I I I\n\
I I A I I B I I\n\
I I I I I I\n\
I ------- ------- I\n\
I I\n\
I I\n\
--------------------------------\n\
";
var lines = s.split('\n');
var outer_box_top_re = /--+/g;
var i;
for (i=0; i<lines.length; i++)
while ((res = outer_box_top_re.exec(lines[i])) != null)
L = res.index
R = outer_box_top_re.lastIndex
process_box(i, L, R)
function process_box(T, L, R)
console.log('<div top="' + T + '" left="' + L + '" right="' + R + '">')
blank_out(T, L, R)
var i = T;
while (1)
i += 1;
if (i >= lines.length)
console.log('Fell off bottom of ascii-art without finding bottom of box');
process.exit(1);
var line = lines[i];
if (line[L] == 'I' && line[R-1] == 'I')
// interior
// Look for (the tops of) sub-boxes.
// (between L+1 and R-2)
var inner_box_top_re = /--+/g;
// Inner and outer need to be separate so that
// inner doesn't stomp on outer's lastIndex.
inner_box_top_re.lastIndex = L+1;
while ((res = inner_box_top_re.exec(lines[i])) != null)
sub_L = res.index;
sub_R = inner_box_top_re.lastIndex;
if (sub_L > R-1) break;
process_box(i, sub_L, sub_R);
// Look for any other content (i.e., a box label)
content = lines[i].substring(L+1, R-1);
if (content.search(/[^ ]/) != -1)
console.log(content);
blank_out(i, L, R);
else if (line.substring(L,R).match(/^-+$/))
// bottom
blank_out(i, L, R);
break;
else
console.log("line " + i + " doesn't contain a valid continuation of the box");
process.exit(1)
console.log('</div>')
function blank_out(i, L, R)
lines[i] = (
lines[i].substring(0,L)
+ lines[i].substring(L,R).replace(/./g, ' ')
+ lines[i].substring(R)
);
【讨论】:
相当不错,尤其是考虑到这是您第一次遇到堆栈溢出! :)以上是关于如何使用 Java 或 Javascript 将 ASCII Art 解析为 HTML? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
如何编写按字母顺序组织数据的 Java 或 Javascript 程序?
如何使用 Angular js 或 java 脚本将逗号分隔的字符串分解为单个索引数组