【问题标题】:How can I parse a code string and build hierarchical array based on { and } in the string如何解析代码字符串并基于字符串中的 { 和 } 构建分层数组
【发布时间】:2011-07-02 18:31:42
【问题描述】:

我有一个类似代码的字符串,如下所示:

a
{
    bcd
    {
        ef
        {
            gh
            {
                i
            }
            j
        }
    }
    k
    {
        lmn
        {
            op
        }
        qr
        {
            st
        }
        uv
        {
            wx
        }
        y
    }
    z
}

我希望解析这个字符串,以便我可以从这个代码创建一个分层数组,其中每棵树都是基于{ 创建的,而一棵树以} 结尾。

数组看起来像:

[
    "a",

    "{",

    [

        "bcd",

        "{",

        [
            "ef",

            "{",

            [
                "gh",

                "{",

                [
                    "i"
                ],

                "}",

                "j"
            ],

            "}"
        ],

        "}",

        "k",

        "{",

        [
            "lmn",
            "{",
            [
                "op"
            ],

            "}",
            "qr",

            "{",

            [
                "st"
            ],

            "}",

            "uv",

            "{",
            [
                "wx"
            ],

            "}",
            "y"
        ],

        "}",
        "z"
    ],

"}"
]

任何人都可以帮助我获得这个算法吗?

您也可以将这些语言中任何一种 Java/C#/PHP/VB.NET/JavaScript/ActionScript 的代码传递给我。

【问题讨论】:

  • 编译器同样会解析代码!!!
  • 因为对于常规数组,您需要在编译时指定数组嵌套的深度,常规数组无法做到这一点。您必须创建包含字符串数组和节点数组的节点。
  • @MrFox:使用 PHP 或 ActionScript/JavaScript 怎么样?
  • @MrFox:不正确。例如,如果所有 {} 都替换为 (),那么他正在查看一个常规的 Lisp 列表。对于大多数其他语言,逗号也是必需的。只需将文件放入您想使用的任何语言的自然形式的数组中,然后让语言进行解析。
  • 当有人发布一个完整的任务而不是一个问题并寻找一个完整的解决方案而不是提示时,它让我想:这到底是什么。你有没有写出一些代码……这只是一个简单的算法。没那么难!您甚至可以通过搜索网络找到一些解决方案

标签: algorithm parsing


【解决方案1】:

如果这就是你想要做的,你可以这样写(C#):

class Node
{
    public string Name { get; private set; }
    public IEnumerable<Node> Children { get; private set; }

    public Node(string name, IEnumerable<Node> children)
    {
        Name = name;
        Children = children;
    }
}

class Parser
{
    public Node Parse(string s)
    {
        return Parse(s.Split(new char[0], StringSplitOptions.RemoveEmptyEntries));
    }

    public Node Parse(IEnumerable<string> tokens)
    {
        using (var enumerator = tokens.GetEnumerator())
        {
            enumerator.MoveNext(); // move to first token
            return Parse(enumerator);
        }
    }

    Node Parse(IEnumerator<string> enumerator)
    {
        string name = enumerator.Current;
        enumerator.MoveNext();
        var children = new List<Node>();
        if (enumerator.Current == "{")
        {
            enumerator.MoveNext();
            while (enumerator.Current != "}")
            {
                children.Add(Parse(enumerator));
            }
            enumerator.MoveNext();
        }
        return new Node(name, children);
    }
}

此代码不检查MoveNext() 的返回值,这意味着它会在无效输入上产生奇怪的结果(包括无限循环的可能性)。

它还要求标记由空格分隔。所以像a{b{c}} 这样的字符串将被解析为一个名称为a{b{c}} 的节点。

创建一个特殊类型Node 比使用弱类型数组要好得多(即使你使用弱类型语言)。并且不需要在结果中包含大括号。

如果你想做更复杂的事情,我建议使用一些解析器库。

如果字符串可能很长并且您从文件或网络中读取它,您可能希望使用某种形式的流而不是普通字符串。

【讨论】:

    【解决方案2】:

    你对语言并不是很挑剔,所以我很好奇你为什么想要这个。下面是一些应该在 C# 中做你想做的事情的代码:

    public static object[] ParseSpecial(string s)
    {
        string dummy = "";
        Stack<List<object>> result = new Stack<List<object>>();
        result.Push(new List<object>());
        foreach (char character in s)
        {
            switch (character)
            {
                case '{':
                    if (dummy.Length > 0)
                        result.Peek().Add(dummy);
                    dummy = "";
    
                    result.Peek().Add("{");
                    result.Push(new List<object>());
                    break;
    
                case '}':
                    if (dummy.Length > 0)
                        result.Peek().Add(dummy);
                    dummy = "";
    
                    List<object> temp = result.Pop();
                    result.Peek().Add(temp.ToArray());
                    result.Peek().Add("}");
                    break;
    
                default:
                    dummy += character;
                    break;
            }
        }
    
        if (dummy.Length > 0)
            result.Peek().Add(dummy);
    
        return result.Peek().ToArray();
    }
    

    【讨论】:

    • 我没有选择一种明确的语言只是为了得到不同语言的开发人员的响应。感谢您的代码。
    • 您的代码不会将a { b c } 的情况作为一个有两个孩子的项目来处理,我认为应该这样做。此外,文本节点包含前导和尾随空格,我认为它们不应该。
    猜你喜欢
    • 1970-01-01
    • 2018-08-31
    • 1970-01-01
    • 2020-06-21
    • 2018-02-10
    • 1970-01-01
    • 1970-01-01
    • 2013-06-22
    • 1970-01-01
    相关资源
    最近更新 更多