【发布时间】:2016-02-13 00:45:41
【问题描述】:
我有一个包含超过 500 万行的文本文件。我需要逐行运行并删除某些行并替换某个字符串。我在 C# 中编写了一些“有效”的代码,但它可能需要将近一天的时间才能完成,这似乎很疯狂,因为在 notepad++ 中进行搜索和替换可以在几分钟内完成。但是,我们需要将其自动化。
文件可以任意包含一行
"<-comment 1: (more text on the line here)"
和
"<-Another line (more text on the line here)"
我想删除以注释 1 或其他行开头的任何行...
还有一个字符串
<tag>—</tag>
我想用下划线代替。这应该只出现在以“LINK:”开头的行上
我目前的代码是:
static void Main()
{
const Int32 BufferSize = 128;
int count = 0;
int count2 = 0;
string filename = @"C:\test\test.txt";
string output = @"C:\text\output.txt";
string Startcomment = @"<-comment 1:";
string Startmoretext= @"<-Another line";
string othercit = @"LINK:";
string sub = @"<tag>—</tag>";
string subrepalce = @"_";
string line;
using (var filestream = File.OpenRead(filename))
{
Console.WriteLine("Start time: " + DateTime.Now.ToString());
using (var streamreader = new StreamReader(filestream, Encoding.UTF8, true, BufferSize))
{
File.WriteAllText(output, "Clean text file" + Environment.NewLine);
while ((line = streamreader.ReadLine()) != null)
{
count++;
if(count % 10000 == 0)
{
Console.WriteLine("Batch complete: " + DateTime.Now.ToString());
Console.WriteLine(count);
}
if(!line.StartsWith(Startcomment) && !line.StartsWith(Startmoretext))
{
count2++;
if (line.StartsWith(othercit))
{
line = line.Replace(sub, subrepalce);
}
File.AppendAllText(output, line + Environment.NewLine);
}
}
}
Console.WriteLine(DateTime.Now.ToString());
Console.WriteLine(count + " Lines processed");
Console.WriteLine(count2 + " Lines written back");
Console.WriteLine("Finished!!!!!!");
Console.Read();
}
}
运行时间不可行。
我想让它在一个正则表达式下运行,如果我们需要添加新的异常,我们可以在脚本之外维护一个配置文件,但似乎也可以永远运行。
static void Main()
{
const Int32 BufferSize = 128;
string filename = @"C:\test\test.txt";
XmlDocument xdoc = new XmlDocument();
xdoc.Load(@"C:\test\RegexConfig.xml");
XmlElement xmlRoot = xdoc.DocumentElement;
XmlNodeList xmlNodes = xmlRoot.SelectNodes("/root/line");
int count = 0;
string line;
using (var filestream = File.OpenRead(filename))
{
Console.WriteLine(DateTime.Now.ToString());
using (var streamreader = new StreamReader(filestream, Encoding.UTF8, true, BufferSize))
{
File.WriteAllText(@"C:\test\output.txt", "Clean file" + Environment.NewLine);
while ((line = streamreader.ReadLine()) != null)
{
string output = line;
foreach (XmlNode node in xmlNodes)
{
string pattern = node["pattern"].InnerText;
string replacement = node["replacement"].InnerText;
Regex rgx = new Regex(pattern);
output = rgx.Replace(output, replacement);
rgx = null;
}
if (output.Length > 0)
{
count++;
if (count % 10000 == 0)
{
Console.WriteLine(count);
Console.WriteLine(DateTime.Now.ToString());
}
File.AppendAllText(@"C:\test\test.txt", output + Environment.NewLine);
}
}
}
Console.WriteLine(DateTime.Now.ToString());
Console.WriteLine("Finished!!!!!!");
Console.Read();
}
}
XML 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<root>
<line>
<pattern><![CDATA[<-comment 1:.*]]></pattern>
<replacement><![CDATA[]]></replacement>
</line>
<line>
<pattern><![CDATA[<-Another line.*]]></pattern>
<replacement><![CDATA[]]></replacement>
</line>
<line>
<pattern><![CDATA[<tag>—</tag>]]></pattern>
<replacement>_</replacement>
</line>
</root>
应该如何做这样的事情才能最有效地工作?
【问题讨论】:
-
与从文件中读取的方式类似,您应该保持输出文件打开并写入其流以允许操作系统缓冲输出。
File.AppendAllText每次都会打开和关闭文件。 -
另外,您可以在 foreach 循环之前编译您的正则表达式。
-
谢谢 C,我应该用什么代替?谢谢 Wilktor 我先研究一下如何编译,这是我第一次尝试使用正则表达式
-
您是否考虑过在 Notepad++ 中录制和播放宏。它可能不是完全自动化的,而是半自动化的,工作量最少。只是我的两分钱。
标签: c# regex filestream