在整个文件中进行多行正则表达式搜索

8

我找到了很多关于如何使用正则表达式替换文件中文本的例子。然而,这可以归结为两个版本:
1. 迭代文件中的所有行,并将正则表达式应用于每一行
2. 加载整个文件。

对于“我的”文件来说,第二种方法不可行——它们大约有2GiB…
至于第一种方法:目前这是我的方法,但我想知道…如果需要应用跨越多行的正则表达式怎么办?


1
能否将这些数据加载到关系数据库管理系统中? - John Gietzen
我认为你需要更好地描述你的数据和正则表达式,才能得到一个合适的建议。 - Jeremy Stein
好的。有时我需要修改大型CSV文件(例如,切换第3列和第5列)。我发现,使用正则表达式和sed,我可以快速应用所需的修改。但是,我使用The Regulator“开发”和测试我的正则表达式,这将导致“clr-regex”,然后必须将其转换为sed语法。为了避免这种情况,我编写了一个小工具(C#),它让我将“clr-regex”应用于文件。 现在:使用此工具无法应用跨越多行的正则表达式 - 因为我正在执行上述方法1。上述问题有些假设。 - Nils
请通过编辑问题而不是添加评论来提供澄清。 - Ryan Gates
Ryan, 谢谢。我想我在2010年左右开始这样做了;-) - Nils
6个回答

2

答案如下:
没有简单的方法

我发现一个StreamRegex-Class可能能够做到我想要的。
从我所理解的算法来看:

  • 从文件开头开始,使用空缓冲区
  • 执行以下步骤 (
    • 将文件的一部分添加到缓冲区中
    • 如果缓冲区中有匹配项
      • 标记匹配项
      • 删除出现在匹配项结束前的所有数据
  • ) 直到文件还有内容可读

这样就不需要加载整个文件 -- 或者至少减少了在内存中加载整个文件的机会...
但是:最坏的情况是整个文件中都没有匹配项 - 在这种情况下,整个文件将被加载到内存中。


2
正则表达式不是解决这些大量文本的好方法。可以创建自己的小解析器:
- 逐行读取文件; - 对于每一行: - 逐字符循环遍历该行,跟踪任何开放/关闭的字符串文字; - 当你遇到'/*'(且不在字符串“内部”)时,存储该偏移量数字,并循环直到遇到第一个'*/'并将该数字也存储下来。
这将为您提供所有注释块的起始和结束偏移量数字。现在,您应该能够通过创建临时文件并将原始文件中的文本写入该临时文件(当然,如果您在注释块中,则要写入其他内容)来替换它们。
编辑:源文件大小为2GiB?

我说过源代码吗?;-) 不是“原始”数据,实际上是CSV格式的。 - Nils
啊,我明白了。虽然不懂C#,但我想象中也不可能创建如此大的源文件。 - Bart Kiers

0

如果您不介意手脏一点(并且您的正则表达式足够简单,或者您非常渴望速度并且不介意受点苦),您可以使用Ragel。它可以针对C#进行优化,尽管该网站没有提到。但是,您需要包装一个FileStream以提供缓冲索引器,或者在64位进程中使用内存映射文件(带有不安全指针)才能处理大文件。


0
也许你可以每次加载2行(或更多,取决于你认为匹配会跨越多少行),并重叠它们,例如:加载1-2行,然后下一个循环加载2-3行,再下一个加载3-4行;并在每个循环中对两行组合进行多行正则表达式匹配。

好主意,但每一行可能需要进行多次正则表达式匹配。必须考虑可能的副作用。 - Nils
嗯,是的,你说得对。也许只有当匹配项在第一行开始(在任何换行符之前)时才进行匹配? - Mark Bell

0
我建议在进行替换之前,您应该对数据进行预解析/规范化,以便每行描述一组需要应用替换的可能数据。否则,您将遇到数据完整性方面的复杂问题,这些问题实际上无法解决,除非还有其他困难。
如果有一种方法可以将数据分成逻辑块,那么您可以构建一个使用MapReduce模式解析数据的程序。

0

我和巴特一样,你应该使用某种解析器来处理这个。

或者,如果您不介意生成子进程,可以直接使用sed(Windows上有本地端口,或者您可以使用Cygwin


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接