我正在处理大小在150MB至250MB之间的文件,并且需要为匹配集合中的每个匹配项添加一个换页符(/f)字符。目前,我每个匹配项的正则表达式如下:
Regex myreg = new Regex("ABC: DEF11-1111(.*?)MORE DATA(.*?)EVEN MORE DATA(.*?)\f", RegexOptions.Singleline);
我希望你能够修改文件中的每个匹配项(然后覆盖该文件),使其成为稍后可以使用较短的正则表达式找到的内容:
Regex myreg = new Regex("ABC: DEF11-1111(.*?)\f\f, RegexOptions.Singleline);
换句话说,我想在文件中每次找到匹配项时简单地附加一个换页符(\f)并保存它。
我在stackoverflow上看到了很多替换文本的例子,但对于较大的文件则不太常见。典型的做法包括:
- 使用streamreader将整个文件存储在字符串中,然后在该字符串中进行查找和替换。 - 使用MatchCollection与File.ReadAllText()结合使用 - 逐行读取文件并在那里查找匹配项。
前两种方法的问题在于它们会消耗大量内存,我担心程序能否处理所有这些内容。第三个选项的问题是我的正则表达式跨越多行,因此无法在单行中找到。我还看到其他帖子,但它们涵盖替换特定文本字符串而不是使用正则表达式。
对于我在文件中找到的每个匹配项附加一个换页符,然后保存该文件的一个好方法是什么?
编辑:
根据一些建议,我尝试玩弄StreamReader.ReadLine()。具体来说,我会读取一行,查看它是否与我的表达式匹配,然后根据结果写入文件。如果它与表达式匹配,我会写入文件。如果它没有匹配表达式,我会将其附加到一个字符串中,直到它匹配表达式。就像这样:
Regex myreg = new Regex("ABC: DEF11-1111(.?)MORE DATA(.?)EVEN MORE DATA(.*?)\f", RegexOptions.Singleline);
//For storing/comparing our match.
string line, buildingmatch, match, whatremains;
buildingmatch = "";
match = "";
whatremains = "";
//For keep track of trailing bits after our match.
int matchlength = 0;
using (StreamWriter sw = new StreamWriter(destFile))
using (StreamReader sr = new StreamReader(srcFile))
{
//While we are still reading lines in the file...
while ((line = sr.ReadLine()) != null)
{
//Keep adding lines to buildingmatch until we can match the regular expression.
buildingmatch = buildingmatch + line + "\r\n";
if (myreg.IsMatch(buildingmatch)
{
match = myreg.Match(buildingmatch).Value;
matchlength = match.Lengh;
//Make sure we are not at the end of the file.
if (matchlength < buildingmatch.Length)
{
whatremains = buildingmatch.SubString(matchlength, buildingmatch.Length - matchlength);
}
sw.Write(match, + "\f\f");
buildingmatch = whatremains;
whatremains = "";
}
}
}
问题在于处理大约150MB的文件需要大约55分钟的时间。必须有更好的方法来解决这个问题...
buildingmatch +=line;
不断地将一行文本添加到缓冲区中。每次添加后,您都会运行相同的正则表达式,该表达式从缓冲区的开头开始搜索。它无法匹配,因为它找不到结尾,因为尚未添加。就像 !N (N阶乘) 一样。想象一下,在缓冲区中搜索Q
,当每次搜索从开头开始时,缓冲区每次扩展1个字符,并且在第10,000次通过后才添加Q
。 - slnABC:DEF11-1111
。如果匹配,则重新开始缓冲。然后在每行中查找结尾\f
,如果没有找到则添加到缓冲区中。如果找到了,则在缓冲区上运行主正则表达式一次。如果匹配,则将记录取出,清除缓冲区并开始寻找新记录。如果不匹配,则继续添加行,但仅检查行以寻找结尾。等等... - sln