4

我今天早些时候遇到了这个问题:

示例输入:我遇到了 Joe 和 Jill,然后我们去购物
示例输出: [TOP [S [S [NP [PRP I]] [VP [VBD ran] [PP [IN into] [NP [NNP Joe] [CC和] [NNP Jill]]]]] [CC and] [S [ADVP [RB then]] [NP [PRP we]] [VP [VBD going] [NP [NN shopping]]]]]]

在此处输入图像描述

我正要建议简单地将预期输出(因为它看起来像一个 s 表达式)解析为一个对象(在我们的例子中是一个树),然后使用简单的 LINQ 方法来处理它。然而,令我惊讶的是,我找不到 C# s-expression 解析器。

我唯一能想到的是使用 Clojure 来解析它,因为它编译为 clr,但我不确定它是否是一个好的解决方案。

顺便说一句,我不介意输出 type 的答案dynamic。我在这里找到的唯一答案是反序列化为特定模式。

总结一下我的问题: 我需要在 C# 中反序列化 s 表达式(序列化对于这个问题的未来读者来说会很好)

4

2 回答 2

7

看起来您需要以下形式的数据结构:

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(" )");
}

以及以下形式的反序列化器:

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;
}

但是,如果还没有测试甚至编译过这段代码,这或多或少是它可以工作的方式。

于 2013-02-03T18:24:22.823 回答
2

我编写了一个开源的 S-Expression 解析器,可以作为S-Expression.NET 使用。由于它使用 OMeta# 来生成解析器,因此您可以快速使用它来添加新功能。

于 2013-02-28T21:57:39.010 回答