我有大量的日志文件,在这里我需要阅读并找到所有错误和错误,如下所示。
TX: 000001270
PROCESSING: 2015-666-001211-0000
CONVERSION FAILURE!
ERROR: the given number not find in transaction table.
Removed TransactionSet
TX: 0000018887
PROCESSING: 2915-966-001888-0000
CONVERSION FAILURE!
ERROR: Object reference not set an instance of object.
Removed TransactionSet
任何人都可以帮我使用正则表达式将所有错误读入数据表/列表中,并显示处理编号和错误消息。 (或)请建议是否还有其他更好的解决方案来阅读本文。
预期输出格式(作为列表或数据表)
Processing | ErrorMessage
-------------------- | ----------------------------------------------
2015-666-001211-0000 | the given number not find in transaction table.
-------------------- | ----------------------------------------------
2915-966-001888-0000 Object reference not set an instance of object.
-------------------- | ----------------------------------------------
答案 0 :(得分:2)
您是否在寻找类似的东西( Linq ):
String prefix = "ERROR: ";
var result = File
.ReadLines(@"C:\MyLog.txt")
.Where(line => line.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
.Select(line => line.Substring(prefix.Length)); // <- let's remove "ERROR: " prefix
// the given number not find in transaction table.
// Object reference not set an instance of object.
String report = String.Join(Environment.NewLine, result);
修改:不幸的是,标准 Linq 并未实施Lag()
或Lead()
方法(但是,更多Linq https://www.nuget.org/packages/morelinq/有他们),所以代码将是精简的:
String processing = "";
var result = File
.ReadLines(@"C:\MyLog.txt")
.Where(line =>
line.StartsWith("ERROR: ", StringComparison.OrdinalIgnoreCase) ||
line.StartsWith("PROCESSING: ", StringComparison.OrdinalIgnoreCase))
.Select(line => { // Lag() emulation
if (line.StartsWith("PROCESSING: ", StringComparison.OrdinalIgnoreCase)) {
processing = line.Substring("PROCESSING: ".Length);
return "";
}
else
return processing + " | " + line.Substring("ERROR: ".Length);
})
.Where(line => !String.IsNullOrEmpty(line));
//2015-666-001211-0000 | the given number not find in transaction table.
//2915-966-001888-0000 | Object reference not set an instance of object.
String report = String.Join(Environment.NewLine, result);
答案 1 :(得分:1)
这是使用字典的解决方案(假设处理编号是唯一的)。基本上当它遇到“PROCESSING:”行时,它会在字典中添加一个带有空字符串的条目,然后在下次遇到“ERROR:”行时,它将设置上一个插入键的值。测试了100万条错误记录(因此700万行,150MB文件大小)需要4.7秒
Dictionary<string, string> Errors = new Dictionary<string, string>();
string lastProcessingNumber = string.Empty;
using (StreamReader reader = new StreamReader("log.txt"))
{
while(!reader.EndOfStream)
{
string line = reader.ReadLine();
if(line.StartsWith("PROCESSING"))
{
lastProcessingNumber = line.Replace("PROCESSING: ", string.Empty);
Errors.Add(lastProcessingNumber, string.Empty);
}
if(line.StartsWith("ERROR") && lastProcessingNumber != string.Empty)
{
Errors[lastProcessingNumber] = line.Replace("ERROR: ", string.Empty);
}
}
}
答案 2 :(得分:1)
对于像这样的事情,正则表达式绝对是一个很好的选择。只要您知道自己在做什么,因为它是一种声明性语言,它可能比任何必要的替代方案更清晰,更简单,更灵活。
正则表达式模式的许多变体都可以使用,它取决于您的具体需求,但是以下模式中的某些内容应该对您有用:
PROCESSING: (?<processing>[^\r\n]*)(.|\r|\n)*?ERROR: (?<error>[^\r\n]*)
您可以像这样使用它:
string pattern = @"PROCESSING: (?<processing>[^\r\n]*)(.|\r|\n)*?ERROR: (?<error>[^\r\n]*)";
foreach (Match m in Regex.Matches(input, pattern))
{
string processing = m.Groups["processing"].Value;
string error = m.Groups["error"].Value;
// Insert into database
}