在C#中解析自定义文件

时间:2010-06-26 02:48:39

标签: c# regex parsing

  1. 我应该使用RegularExpressions来执行此操作吗?
  2. 可以将结果构造为可查询,IEnumerable等
  3. 我有一个文件,我无法改变它的生成方式。我希望创建一个解析器类来提取所有数据。理想情况下,我想使用此类打开该文件,并让它返回一个我可以使用的可查询数组类型结构。

    数据的结构如下:

    ["Table"] = {
        ["Text"] = { 
            ["Number"] = { 
                "Item", --[1]
                "Item", --[2]
                "Item", --[3]
            },
        --repeat--
    Note that the actual file has line brakes, tab, etc. (\n\t\t) 
    As you will see the patters I use take this into account 
    to get different levels.
    

    我有一个为vb6为这个文件编写的正则表达式,但是7个模式中的1个不起作用:

    @"^\t\[""([\s\S]*?)""] = {([\s\S]*?)^\t},$
    

    这应该将最高级[“表”]分组到他们自己的匹配中。但它返回0并且很慢。如果我取出$符号,它也会返回所有子节点。这是阻止我使用正则表达式执行此操作的唯一方法。

    另一种选择就是逐行解析我猜。我确信我可以在给定的时间内弄清楚这一点,但在我走向某种方式之前,我想听听其他意见。

    有什么想法吗?

5 个答案:

答案 0 :(得分:3)

我会远离正则表达式,如果你想在这样的文件上进行任何真实的解析,你会很快遇到Regex的大量不可解决的问题,例如处理正确的嵌套(假设你的文件可以有多个)嵌套水平)和正确性将导致你如此头痛。有许多模式可以导致任何正则表达式处理器几乎看起来像一个无限循环并且永远不会结束(或者至少在任何合理的时间内都没有),并且真正编写这样一个简单的解析器应该很快并且可以带来更好的调试,性能和可维护性等等。

答案 1 :(得分:1)

跟着你的直觉去吧。正则表达式是处理此问题的正确方法。如果您可以发布样本,我可以帮助您编写RegEx以匹配您想要的任何内容: - )

快速轻松测试正则表达式的一种方法是转到http://rubular.com/

它可以动态显示与您的样本相匹配的内容。您可以快速微调您的表达。

答案 2 :(得分:1)

我猜你的结构与Lua有关。至少它的外观应该是Lua可以随时读取的。如果我是对的,您可能需要查看luainterface

此处还有一些其他问题,例如代码:Parse a Lua DatastructureRead nested Lua table

答案 3 :(得分:0)

不要使用正则表达式 - 获取适当的解析器,您可以在其中放入语法文件。与REGEX相比,这样可以轻松地进行更复杂的解析。

答案 4 :(得分:0)

问题#1实际上回答了自己。事实上,这是一个教科书的例子,说明在许多情况下应该避免使用正则表达式的两大理由。

  • 你继承了一个有效的正则表达式,但现在它需要调整,你店里的任何人都没有必要的专业知识。

  • 数据具有递归或层次结构,正则表达式特别不适合。

你的正则表达式通过欺骗来解决递归问题;它使用每行前导空格的长度来推断哪个分隔符与哪个分隔符相关。 可以使用.NET的递归匹配功能正确地完成它,但它会非常非常难看。所以,让我们看看我们可以用你所拥有的东西做什么。

@"^\t\[""([\s\S]*?)""] = {([\s\S]*?)^\t},$"

您的性能问题几乎可以肯定是由于第二个[\s\S]*? - 顺便说一句,应该是.*?并设置了单线模式;只有JavaScript需要[\s\S]黑客攻击。但无论你怎么写它,你都要求它做太多的工作。我就是这样做的:

@"^\t\[""([^""]*)""\] *= *{(?>.*\n)*?\t}," // Multiline ON, Singleline OFF

您一次将一个字符与[\s\S]*?匹配,我一次匹配一行(?>.*\n)*?。不情愿的量词非常方便,但如果你过度劳累,那么你可以和贪婪的量词一起解决它们。

我仍然在开头使用^锚点,但我不必在其他地方使用锚点,因为我明确地匹配了所有换行符。虽然为了清楚起见,我在此示例中使用\n,但我通常使用(?:\r\n|[\r\n])来匹配三个最常见的行分隔符中的任何一个:\r\n(Windows),\r(较旧的Mac)和\n(Unix / Linux / OSX)。