解析任意用户输入

时间:2010-01-18 07:30:50

标签: parsing user-input

我有一个充满来自公告板的消息的数据库。该板使用BB代码作为格式化样式。即:

  • 我没有格式化
  • 这是[b]粗体[/ b]文字
  • 标签也可以[i] [b]是[/ b]嵌套[/ i]
  • [b]嵌套[i]可以[/ b]而不是[/ i]丑陋

我的最终目标是将这些消息转换为一些格式良好的XML(此处不讨论;))。我不想使用正则表达式,它会在某些时候失败(事实上它确实如此)。

第一步:将消息解析为某种内部表示(图形,树等)。而且我在这一点上陷入困​​境。实际提取不是一个大问题,但存储是。

如何将这种标记表示为一些有意义的结构。我的问题似乎与从HTML文件构建DOM的浏览器类似(或几乎相同)。所以我认为有一些策略可以解决它。我知道解决方案不会很完美,但我愿意投入大量时间来尽可能地做好。

问题:您有任何提示/提示/评论吗?你可以推荐任何文章或纸张?还是一本讨论这些主题的书?我很感激任何意见。

1 个答案:

答案 0 :(得分:2)

[b]嵌套[i]可以[/ b]而不是[/ i]丑陋

我编写了一个非常类似于你想要做的解析器,除了它会在你的第四个例子上引发错误。 “[i]”中的“意外结束标记[/ b]”的效果。

我认为你想做的事情是非常可行的,但在内部你会想要创建一个树,好像你的原始文本是:

"And the [b]nesting [i]can be[/i][/b][i] rather[/i] ugly"。 (如果您以后不需要将其转换为XML,我认为这不是必需的。如果不需要转换为XML,您可以保留一个文本部分的链接列表,其中每个部分都标有其格式组合)

我想到了解决这个问题的两种可能方法(当然可能有更好的可能性)。 1)预处理并插入缺失的末端并在必要时开始标记。 2)构建你的解析树,并且有重叠标签的地方暗示了基于当前上下文的缺失标签。我认为方法编号(2)会更简单,更清晰。

您可以根据具有AbstractElement类的复合模式,扩展AbstractElement的TextElement类以及扩展AbstractElement的Tag类来建模树,并包含AbstractElement类型的子元素列表。

您首先要创建一个根Tag实例。然后,您将调用rootTag.parse(text)。您需要一台可以返回3种令牌的扫描仪:文本,开始标签和结束标签。扫描仪允许您将令牌推到它上面,它会在任何正常的扫描令牌之前返回。这将允许您在遇到并处理意外结束标记后推送新的开始标记令牌。您还必须知道何时完成输入。我将使用第四种令牌类型。

    /* methods within class Tag */
    public void parse(String text) {
        MyScanner scanner = new MyScanner(text);
        parse(scanner);
    }

    /* returns next token */
    private Token parse(MyScanner scanner) {
        Token firstToken = scanner.getNextToken();
        return parse(scanner,firstToken);
    }

    private Token parse(MyScanner scanner) {
        Token firstToken = scanner.getNextToken();
        return parse(scanner,firstToken);
    }

    private Token parse(MyScanner scanner, Token token) {
        while (!token.isDone() && !token.isEndTag()) {
            if (token.isStartTag()) {
                Tag subTag = new Tag(token.getValue());
                token = scanner.getNextToken();
                token = subTag.parse(scanner,token);
                addElement(subTag);
            }

            else {
                TextElement text = new TextElement(token.getValue());
                addElement(text);
                token = scanner.getNextToken();
            }
        }

        if (token.isEndTag()) {  
            if (!token.getValue().equals(getName()) {
                scanner.push(new Token(Token.START_TAG,token.getValue()));
            }
            else {
                token = scanner.getNextToken();
            }
        }

        return token;
    }

所以如果你要解析“并且[b]嵌套[i]可以[/ b]而不是[/ i]丑陋”,应该创建以下内容。

rootTag.parse should be adding:
    TextElement: "And the "
    Tag: "b"
            TextElement: "nesting "
            Tag: "i"
                    TextElement: "can be"
                    (... at this point the odd [/b] is encountered ...)
                    (... push "i" start tag on the scanner ...)
            (... here the [/b] is encountered (again) ...)
     Tag: "i" (this was scanned because it had been pushed to the scanner)
            TextElement: " rather"
     TextElement: " ugly"

注意:文本区域内的编码不适合测试和调试。接受这个答案作为暗示或可能性,而不是你的肯定答案。