【问题标题】:S-Expressions parsingS-表达式解析
【发布时间】:2013-02-03 17:47:34
【问题描述】:

我今天早些时候遇到了this question

示例输入:我遇到了 Joe 和 Jill,然后我们去购物
示例输出: [顶部 [S [S [NP [PRP I]] [VP [VBD 跑] [PP [IN 进入] [NP [NNP 乔] [CC 和] [NNP 吉尔]]]]] [CC 和] [S [ADVP [RB 然后]] [NP [PRP我们]] [VP [VBD去] [NP [NN购物]]]]]]

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

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

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

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

【问题讨论】:

  • 丹尼,谢谢你的编辑(虽然我不确定为什么图片是相关的,我相信你有更多的经验)。我在你的描述中看到你知道 LISP 和 .NET,我很想得到你的建议。
  • 你的意思是(反)序列化已经以 [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 go] [NP [NN shopping]] ]]]] 还是你指的是输入表达式?
  • 我希望能够(反)序列化 s 表达式,在这种情况下是的,我希望能够反序列化上面提到的表达式(嗯,用 ( 代替 [ 和 ) ])

标签: c# clojure s-expression


【解决方案1】:

看起来你需要一个表单的数据结构:

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

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

【讨论】:

  • +1 谢谢 :) 你做的真棒。明天我将研究这段代码并彻底阅读。我只是很失望没有更规范的方法来做到这一点。您应该将此代码放在 github 和 nuget 中,以便其他人能够享受此代码:)
  • 正如我所写的,我什至还没有编译它,所以它需要调试。我还没有在 GitHub 或类似的地方发布任何代码,我总是想去。不过,我不确定有多少人会觉得这很有用。
  • 我愿意。另外,我相信这个答案意味着没有广泛使用的库可以解析 C# 中的 S-Expressions。我认为他们会制作一种有趣的数据交换格式。
  • 我没有搜索图书馆,但是,如果有的话,我想你会找到的。
  • 真的有人编译过这段代码吗?我试过了,即使从语法错误中清除它也不起作用....
【解决方案2】:

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

【讨论】:

  • 你知道如何修改 .ometacs 以支持包括 uderscore 字符和点的符号(也适用于数字)?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-05
  • 1970-01-01
相关资源
最近更新 更多