如何使用 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 代码。例如&lt;space&gt; to &amp;nbsp; line break to &lt;br/&gt; etc

http://jsfiddle.net/kenthaha/9rCXP/

希望它成功。

【讨论】:

在 jsfiddle 中,输出是 ascii 艺术。如何使用 ascii 艺术从 ascii 艺术生成 html 请注意,如果这个的问题,答案就是style="font-family: monospace; white-space: pre",或者更简单,“把它放在&lt;pre&gt;标签中” @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?

如何将javascript代码编译为c++或java

如何编写按字母顺序组织数据的 Java 或 Javascript 程序?

如何使用 Angular js 或 java 脚本将逗号分隔的字符串分解为单个索引数组

如何使用 PayPal 的 SDK(Java 或 JavaScript)实现两步或更少步完成订单?

如何在不传输整个文件的情况下限制使用 JavaScript(或 Java)上传的文件的大小?