2013-02-03 492 views
3

我今天早些時候衝進this questionS-表達式解析

例輸入:我遇到了喬和吉爾,然後我們去逛街
輸出示例: [TOP [ S [[NP [PRP I]] [VP [VBD ran] [PP [IN into] [NP [NNP Joe] [CC and] [NNP Jill]]]]] [CC and] [S [ADVP [RB then]] [NP [PRP we]] [VP [VBD去] [NP [NN購物]]]]]]

enter image description here

我正要建議簡單地解析預期輸出(因爲它看起來像s表達式)到一個對象(在本例中是樹),然後用簡單的LINQ的方法來處理它。但是,令我驚訝的是,我無法找到C#的s表達式解析器。

我唯一能想到的就是使用Clojure解析它,因爲它編譯爲clr,但我不確定它是否是一個好的解決方案。

順便說一句,我不介意類型dynamic輸出的答案。我在這裏找到的答案只是反序列化成一個特定的模式。

綜上所述,我的問題: 我需要反序列化在C#s表達式(序列化將是這個問題的未來的讀者好聽)

+0

丹尼,感謝您的編輯(儘管我不確定爲什麼圖像是相關的,我相信,因爲您有更多的經驗)。我在你的描述中看到你知道LISP和.NET,並且我會喜歡你的建議。 –

+0

您的意思是(de)序列化已經以* [TOP [S [S [NP [PRP I]] [VP [VBD ran] [PP [IN into] [NP [NNP Joe] [CC and] [NNP Jill]]]]] [CC and] [S [ADVP [RB then]] [NP [PRP we]] [VP [VBD去] [NP [NN購物]]]]]] *或者你是指到輸入表達式? –

+0

我希望能夠(通常)序列化s表達式,在這種情況下,是的,我想能夠反序列化上述表達式(以及,替換(for [和] for)) –

回答

6

它看起來像您需要的表單的數據結構:

public class SNode 
{ 
    public String Name { get; set; } 

    private readonly List<SNode> _Nodes = new List<SNode>(); 
    public ICollection<SNode> Nodes { get { return _Nodes; } } 
} 

形式

public String Serialize(SNode root) 
{ 
    var sb = new StringBuilder(); 
    Serialize(root, sb); 
    return sb.ToString(); 
} 

private void Serialize(SNode node, StringBuilder sb) 
{ 
    sb.Append('('); 

    sb.Append(node.Name); 

    foreach (var item in node.Nodes) 
     Serialize(item, sb); 

    sb.Append(")"); 
} 

和t的解串器的串​​行化他的形式:

public SNode Deserialize(String st) 
{ 
    if (String.IsNullOrWhiteSpace(st)) 
     return null; 

    var node = new SNode(); 

    var nodesPos = String.IndexOf('('); 
    var endPos = String.LastIndexOf(')'); 

    var childrenString = st.SubString(nodesPos, endPos - nodesPos); 

    node.Name = st.SubString(1, (nodesPos >= 0 ? nodePos : endPos)).TrimEnd(); 

    var childStrings = new List<string>(); 

    int brackets = 0; 
    int startPos = nodesPos; 
    for (int pos = nodesPos; pos++; pos < endPos) 
    { 
     if (st[pos] == '(') 
      brackets++; 
     else if (st[pos] == ')') 
     { 
      brackets--; 

      if (brackets == 0) 
      { 
       childStrings.Add(st.SubString(startPos, pos - startPos + 1)); 
       startPos = pos + 1; 
      } 
     } 
    } 

    foreach (var child in childStrings) 
    { 
     var childNode = Deserialize(this, child); 
     if (childNode != null) 
      node.Nodes.Add(childNode); 
    } 

    return node; 
} 

如果還沒有測試甚至編譯這段代碼,但是,這或多或少是如何工作的。

+0

+1謝謝你:)對你來說真是太棒了。我會研究這些代碼,明天徹底閱讀。我只是感到失望,沒有更多的標準方法來做到這一點。你應該把這段代碼放在github和nuget中,這樣其他人就可以享受:) –

+0

正如我寫的,我甚至沒有編譯它,所以它需要調試。我還沒有在GitHub上發佈任何代碼或者類似的東西,我總是想要去解決這個問題。我不確定有多少人會覺得這有用。 –

+0

我會的。另外,我相信這個答案意味着在C#中沒有廣泛使用的解析S表達式的庫。我認爲他們會製作一個數據交換格式。 –

2

我寫了一個開源的S表達式解析器,可以用作S-Expression.NET。由於它使用OMeta#來生成解析器,因此可以快速使用它來添加新功能。

+1

哇謝謝:)這看起來很有趣 –

+0

你知道如何修改.ometacs來支持符號,包括uderscore字符和點(也用於數字)嗎? – weirdgyn