【问题标题】:Parse a custom file in C#在 C# 中解析自定义文件
【发布时间】:2010-06-26 02:48:39
【问题描述】:
  1. 我应该使用正则表达式来执行此操作吗?
  2. 可以将结果构造为可查询、可 IEnumerable 等。

我有一个文件,我无法更改它的生成方式。我希望创建一个解析器类来提取所有数据。理想情况下,我想使用此类打开文件并让它返回我可以使用的可查询数组类型结构。

数据的结构如下:

["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},$

这应该将最顶层的 ["Table"] 分组到他们自己的匹配中。但它返回 0 并且速度很慢。如果我去掉 $ 符号,它也只会返回所有子节点。这是阻止我使用正则表达式执行此操作的唯一原因。

我猜另一种选择就是逐行解析。我确信我可以在给定的时间内解决这个问题,但我想在我采取一种或另一种方式之前听听其他意见。

有什么想法吗?

【问题讨论】:

  • 您要从中提取的数据在哪里?每个分组中是否有 Table、Text、Number、Item、1、2、3 常量值?

标签: c# regex parsing


【解决方案1】:

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

【讨论】:

  • +1 - 解析器可能更正确。找一个可以让你提出“正确的语法”的方法,这对于复杂的语法要好得多。
【解决方案2】:

我猜你的结构是 Lua 相关的。至少从外观上看,Lua 应该可以随时阅读。如果我是对的,您可能想查看luainterface

这里还有一些其他问题的示例代码:Parse a Lua DatastructureRead nested Lua table

【讨论】:

【解决方案3】:

凭直觉行事。正则表达式是处理这个问题的正确方法。如果您可以发布示例,我可以帮助您编写正则表达式以匹配您想要的任何内容:-)

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

它会实时向您显示与您的样本的匹配项。让您可以快速微调您的表达方式。

【讨论】:

    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      问题 #1 实际上可以自行回答。事实上,这是一个教科书示例,说明了在许多情况下应避免使用正则表达式的两大原因。

      • 您继承了一个有效的正则表达式,但现在需要对其进行调整,而且您的商店中没有人具备必要的专业知识。

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

      您的正则表达式通过作弊解决了递归问题;它使用每行前导空格的长度来推断哪个分隔符与哪个分隔符。您可以使用 .NET 的递归匹配功能正确地做到这一点,但它会非常非常难看。因此,让我们看看我们可以用您所拥有的东西做些什么。

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

      你的性能问题几乎肯定是由于第二个[\s\S]*?--顺便说一下,应该是.*?,设置了单行模式;只有 JavaScript 需要 [\s\S] hack。但无论你用哪种方式写它,你都在要求它做太多的工作。以下是我的做法:

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

      您一次匹配一个字符与[\s\S]*?,我一次匹配一整行与(?>.*\n)*?。不情愿的量词非常方便,但如果你过度使用它们,你可能会遇到与贪婪的量词一样多的麻烦。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-04-23
        • 1970-01-01
        • 2019-08-12
        • 2016-12-17
        • 1970-01-01
        • 2023-01-17
        • 1970-01-01
        相关资源
        最近更新 更多