将字符串解析为树结构?

时间:2010-09-29 22:35:44

标签: parsing clojure tree text-processing text-parsing

我正在试图弄清楚如何将这种格式的字符串解析成任意深度的数据结构树。

"{{Hello big|Hi|Hey} {world|earth}|{Goodbye|farewell} {planet|rock|globe{.|!}}}"

[[["Hello big" "Hi" "Hey"]
  ["world" "earth"]]
 [["Goodbye" "farewell"]
  ["planet" "rock" "globe" ["."
                            "!"]]]]

我尝试过使用一些正则表达式(例如#“{([^ {}] *)}”),但我尝试的所有内容似乎都将树“压平”成一个大的列表名单。我可能从错误的角度接近这个,或者正则表达式不适合这项工作。

感谢您的帮助!

4 个答案:

答案 0 :(得分:9)

不要将正则表达式用于此任务。一种更简单的方法是用语法(BNF或EBNF)描述你的字符串,然后编写一个解析器来根据语法解析字符串。您可以从EBNF和BNF生成一个解析树,因此您自然会得到树结构。

你可以从这样的事情开始:

element      ::= element-type, { ["|"], element-type }
element-type ::= primitive | "{", element, "}"
primitive    ::= symbol | word
symbol       ::= "." | "!"
word         ::= character { character }
character    ::= "a" | "b" | ... | "z"

注意:我写得很快,所以可能不完全正确。但它应该给你一个想法。

答案 1 :(得分:4)

尝试将整个事物与单个正则表达式进行匹配不会让你太过分,因为正则表达式最多输出一个匹配的子字符串位置列表,没有树状结构。你想要一个像这样的词法分析器或语法:

将输入划分为标记 - 原子碎片如'{','|'和'world',然后按顺序处理这些标记。从具有单个根节点的空树开始。

每次找到{时,都会创建并转到子节点。

每当您找到|时,请创建并转到同级节点。

每次找到}时,请转到父节点。

每次找到单词时,将该单词放在当前叶节点中。

答案 2 :(得分:3)

如果你想快速入侵:

  • 用{
  • 替换{chars
  • 将{chars替换为]
  • 替换|带空格的字符
  • 希望你不要输入空格。

read因此它出现在嵌套数组中。

ps:我同意reg-ex不能这样做。

pss:set * read-eval *为false(你不希望输入运行它自己)

答案 3 :(得分:1)

您可以使用amotoen构建语法并解析它:

(ns pegg.core
  (:gen-class)
  (:use
   (com.lithinos.amotoen
    core string-wrapper))
  (:use clojure.contrib.pprint))

(def input "{{Hello big|Hi|Hey} {world|earth}|{Goodbye|farewell} {planet|rock|globe{.|!}}}")

(def grammar
     {
      :Start :List
      :ws #"^[ \n\r\t]*"
      :Sep "|"
      :String #"^[A-Za-z !.]+"
      :Item '(| :String :List)
      :Items [:Item '(+ [:Sep :Item])]
      :List [:ws "{" '(* (| :Items :Item)) "}" :ws]
      })

(def parser (create-parser grammar))

(defn parse
  [^String input]
  (validate grammar)
  (pprint (parser (wrap-string input))))

结果:

pegg.core> (parse input)
{:List [{:ws ""} "{" ({:Item {:List [{:ws ""} "{" ({:Items [{:Item {:String "Hello big"}} ([{:Sep "|"} {:Item {:String "Hi"}}] [{:Sep "|"} {:Item {:String "Hey"}}])]}) "}" {:ws " "}]}} {:Items [{:Item {:List [{:ws ""} "{" ({:Items [{:Item {:String "world"}} ([{:Sep "|"} {:Item {:String "earth"}}])]}) "}" {:ws ""}]}} ([{:Sep "|"} {:Item {:List [{:ws ""} "{" ({:Items [{:Item {:String "Goodbye"}} ([{:Sep "|"} {:Item {:String "farewell"}}])]}) "}" {:ws " "}]}}])]} {:Item {:List [{:ws ""} "{" ({:Items [{:Item {:String "planet"}} ([{:Sep "|"} {:Item {:String "rock"}}] [{:Sep "|"} {:Item {:String "globe"}}])]} {:Item {:List [{:ws ""} "{" ({:Items [{:Item {:String "."}} ([{:Sep "|"} {:Item {:String "!"}}])]}) "}" {:ws ""}]}}) "}" {:ws ""}]}}) "}" {:ws ""}]}

P.S。这是我的第一个peg语法之一,它可以更好。另请参阅http://en.wikipedia.org/wiki/Parsing_expression_grammar