使用文本分析/正则表达式将大文本文件拆分为多个较小的文本文件

时间:2016-10-26 21:53:27

标签: regex windows powershell scripting

我有一个恼人的问题,我已经为第三方提供了一个文件,基本上是一组庞大的类(C#供参考)。我现在已经对这个类进行了多次修订,由于某些未知的原因,第三方开发人员将文件中的类从修订版移到修订版。这使得对其先前版本的任何更改的处理成为问题且耗时。

public class Abc
{
  ...
}

public class Xyz
{
  ...
}

因此,我希望能够将他们提供的文件拆分成多个文件(以他们的类命名,例如Abc.cs,Xyz.cs等)。我还有一些文件,但至少我能够轻松地看到任何更改,因为我可以在交付的文件上运行相同的脚本,并且可以对生成的文件执行差异以确定任何修订到那个特定的班级。

我同时拥有Powershell和Regex的经验,我认为这在PS中是可能的,但老实说,我的头撞到了一堵砖墙。在我有些蹩脚的尝试中,我设法从文件中提取每个结束类括号(}),仅此而已。我还尝试在"\r\npublic class ""\r\n}"\r\npublic class(.*)\r\n}\r\n)之间重复一切,但这导致只输出第一个类,整个文件被移动或根本不工作。这清楚地表明我没有迭代public class的实例,而且我的例子非常类似于更适合拆分CSV而不是多行解决方案的解决方案。

应该注意的是,在所有情况下,public class声明和结束括号都在新行上,所以不应该出现任何边缘情况。该文件不是特别大(<2MB),通过Get-Content读取它根本不需要。我最初的研究建议我使用StreamReader,但这对我的用例来说是不必要的过度杀伤。

这里非常感谢任何正确方向的指示。

非常感谢提前

2 个答案:

答案 0 :(得分:1)

这里有一些我可以为你效劳的东西,假设你只想提取公共课:https://regex101.com/r/urLWuz/2

(public\s*class\s*(\S*)\s*\{.*?(?:\}(?=\s*(?:(?:public\s*class)|$))))
  • ( - 开始包含整个班级的捕获组

    • public\s*class\s*(\S*) - 匹配类声明和捕获名称。 \s将匹配任何空格,\S将匹配任何非空格
    • \s*\{ - 匹配班级内容的开头大括号
    • .*? - 内部任何东西的懒惰匹配。如果这是贪婪的话,它会将所有类匹配为一个匹配。
    • (?:\}(?=\s*(?:(?:public\s*class)|$))) - 匹配使用非捕获组结束班级内容的大括号
      • \}(?=\s*(?:(?:public\s*class)|$)) - 使用一个肯定的前瞻匹配结束括号,该前瞻声明在结束括号后面是可选的空格,后跟另一个类或文件的结尾。如果不考虑文件结束的可能性,则不会捕获最后一个类。非捕获组用于分组捕获。
  • ) - 关闭整个匹配类的捕获组

这应该捕获每个类以及类名。基本上,它通过检查括号后面的类声明或文件的结尾来知道哪个大括号是该类的右括号。

如果所有类都在命名空间内,则需要稍微修改。

答案 1 :(得分:1)

在行开始时按public class拆分:

(Get-Content r:\1.cs | Out-String) -split '(?:^|\r\n)public class\s+' -ne '' | 
    ForEach {
        $className = $_ -replace '(?s)^(\w+).*$', '$1'
        "public class $_" | Out-File "r:\$className.cs" -encoding UTF8
    }

调整菜谱方案:

在PS3.0 +中:使用(Get-Content r:\1.cs -raw)代替(Get-Content r:\1.cs | Out-String)
在任何PS中:[IO.File]::ReadAllText('r:\1.cs')甚至更快。