用C#解析文本文件的最佳方法?

时间:2020-03-05 18:40:13  来源:igfitidea点击:

我想解析一个配置文件,例如:

[KEY:Value]     
    [SUBKEY:SubValue]

现在,我从StreamReader开始,将行转换为字符数组,当时我发现必须有更好的方法。因此,请谦虚的读者向我提供帮助。

一个限制是它必须在Linux / Mono环境中工作(确切地说是1.2.6)。我没有(Mono)的最新2.0版本,因此请尝试将语言功能限制为C2.0或者C1.0。

解决方案

回答

在我看来,最好使用基于XML的配置文件,因为已经有.NET类可以相对轻松地为我们读取和存储信息。是否有理由无法做到这一点?

@Bernard:的确,手工编辑XML很繁琐,​​但是我们要呈现的结构已经看起来与XML非常相似。

然后,是的,那里有一个好的方法。

回答

我们还可以使用堆栈,并使用推入/弹出算法。这与打开/关闭标签匹配。

public string check()
    {
        ArrayList tags = getTags();

        int stackSize = tags.Count;

        Stack stack = new Stack(stackSize);

        foreach (string tag in tags)
        {
            if (!tag.Contains('/'))
            {
                stack.push(tag);
            }
            else
            {
                if (!stack.isEmpty())
                {
                    string startTag = stack.pop();
                    startTag = startTag.Substring(1, startTag.Length - 1);
                    string endTag = tag.Substring(2, tag.Length - 2);
                    if (!startTag.Equals(endTag))
                    {
                        return "Fout: geen matchende eindtag";
                    }
                }
                else
                {
                    return "Fout: geen matchende openeningstag";
                }
            }
        }

        if (!stack.isEmpty())
        {
            return "Fout: geen matchende eindtag";
        }            
        return "Xml is valid";
    }

我们可能可以进行调整,以便可以读取文件的内容。正则表达式也是一个好主意。

回答

前几天,我几乎在研究这个确切的问题:有关字符串标记化的这篇文章正是我们所需要的。我们将需要将令牌定义为以下形式:

@"(?&ltlevel>\s) | " +
@"(?&ltterm>[^:\s]) | " +
@"(?&ltseparator>:)"

这篇文章很好地解释了它。从那里开始,只要我们认为合适,就可以开始食用代币。

提示:对于LL(1)解析器(读取:简单),令牌不能共享前缀。如果使用abc作为令牌,则不能使用ace作为令牌

注意:文章缺少|示例中的字符,只需将它们放入。

回答

I considered it, but I'm not going to use XML. I am going to be writing this stuff by hand, and hand editing XML makes my brain hurt. :')

我们看过YAML吗?

我们将获得XML的好处,而无需所有的痛苦。在ruby社区中,它被广泛用于配置文件,预先准备的数据库数据等内容。

这是一个例子

customer:
  name: Orion
  age: 26
  addresses:
    - type: Work
      number: 12
      street: Bob Street
    - type: Home
      number: 15
      street: Secret Road

这里似乎有一个图书馆,我个人没有使用过,但是yaml很简单,所以"它有多难?" :-)

我想说最好是发明自己的即席格式(并处理解析器错误)

回答

最好总是使用库来滚动自己的库。这是"哦,我永远不需要/我没有考虑过"要点的快速列表,这些要点最终会在以后引起注意:

  • 转义字符。如果要在键中输入:或者在值中输入]怎么办?
  • 转义转义字符。
  • 统一码
  • 制表符和空格的混合(请参阅Python的空格敏感语法的问题)
  • 处理不同的返回字符格式
  • 处理语法错误报告

就像其他人建议的那样,YAML看起来是最好的选择。

回答

无论采用哪种持久格式,使用Regex都是最快的解析方式。
在ruby中,可能只有几行代码。

\[KEY:(.*)\] 
\[SUBKEY:(.*)\]

这两个将在第一组中为我们提供Value和SubValue。查看MSDN,了解如何将正则表达式与字符串进行匹配。

这是每个人都应该拥有的小猫咪。正则表达式前的日子似乎就像冰河时期。

回答

@吉寿

实际上,一旦我适应了转义字符,我的正则表达式的运行速度就比我手写的自上而下的递归解析器慢了一点,而且没有嵌套(将子项链接到其父母)和错误报告了手写解析器。

正则表达式的编写速度稍快(尽管我确实有一些手工解析器的经验),但这并没有好的错误报告。一旦添加,它就会变得有点困难,并且需要更长的时间。

我还发现手写解析器更容易理解其意图。例如,下面是代码片段:

private static Node ParseNode(TextReader reader)
{
    Node node = new Node();
    int indentation = ParseWhitespace(reader);
    Expect(reader, '[');
    node.Key = ParseTerminatedString(reader, ':');
    node.Value = ParseTerminatedString(reader, ']');
}

回答

.NET的另一个YAML库正在开发中。目前,它支持读取YAML流,并且已经在Windows和Mono上进行了测试。当前正在执行写支持。