我有一个充满来自公告板的消息的数据库。该板使用BB代码作为格式化样式。即:
我的最终目标是将这些消息转换为一些格式良好的XML(此处不讨论;))。我不想使用正则表达式,它会在某些时候失败(事实上它确实如此)。
第一步:将消息解析为某种内部表示(图形,树等)。而且我在这一点上陷入困境。实际提取不是一个大问题,但存储是。
如何将这种标记表示为一些有意义的结构。我的问题似乎与从HTML文件构建DOM的浏览器类似(或几乎相同)。所以我认为有一些策略可以解决它。我知道解决方案不会很完美,但我愿意投入大量时间来尽可能地做好。
问题:您有任何提示/提示/评论吗?你可以推荐任何文章或纸张?还是一本讨论这些主题的书?我很感激任何意见。
答案 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"
注意:文本区域内的编码不适合测试和调试。接受这个答案作为暗示或可能性,而不是你的肯定答案。