我需要分析第三方工具创建的结果文件。因此,我尝试创建一个小型c#工具,它应该加载文件内容并执行正则表达式。内容如下:
[1] <Download> 13.01.2016 15:16:47
[
Name: foobar.tif
Status: 0 (ok)
]
[2] <Download> 13.01.2016 15:17:50
[
Name: foobar2.tif
Error: 7100: No file found!
]
[3] <Upload> 13.01.2016 15:17:53
[
Name: Company.tif
Size: 3476
Error: 7200: Unauthorized!
]
...
我尝试创建一个匹配此类内容的正则表达式模式。在此示例中,3个匹配包括我需要检查的4个组(索引1,2或3;任务下载/上载,文件名和状态或错误的值)。可以忽略所有其他信息,如时间戳或可选的“大小”属性。
这就是我的想法:
(?<Index>\[[0-9]+\]) (?<TaskName><[\w]+>)
但是现在这只匹配索引和任务名称,我不知道如何继续获取“名称”和“状态”或“错误”值,因为它们在另一行中。
编辑:
好的,我试图完成你的回答,这是我到目前为止所提出的:
\[(?<Index>[0-9]+?)\]\s<(?<Task>\w+?)>.+\n+\[[\s.]+Name\:\s(?<Name>.+)(?<Content>[\s\S]+?)\]
现在我得到索引,任务名称和名称。到目前为止方法还可以吗?接下来,我将尝试将错误/状态记录到组中。
答案 0 :(得分:3)
默认情况下,正则表达式模式总是捕获多行。这种行为可以被覆盖,但如果这是你想要做的事情,那么你需要做的就是让它跨多行捕获。但是,有一些角色类会考虑换行字符。最值得注意的是,.
字符类匹配除换行符之外的所有字符。因此,如果您想要捕获包含换行符在内的任何字符,则不能只使用.*
,因为这只会匹配到当前行的结尾。
您可以使用(.|\n)*
但是,如果可能,最好使用否定的字符类。例如,如果您需要在以下示例中获取括号内的值:
[Value One] some
random
data
[Value Two]
您可以使用(\[(?<value>[^]]*)\][^[]*)*
。请注意,[^]]*
用作括号内值的模式,[^[]*
用作括号内所有内容的模式。否定的字符类只意味着它匹配列表中不是的任何字符。例如,[^abc]
将匹配任何非a
,b
或c
的字符。所以,[^[]
只意味着任何不是开放方括号的字符。由于换行符不是方括号,因此它将匹配换行符以及任何其他类型的字符。
我之所以说一个否定的字符类比(.|\n)*
之类的东西更可取的原因是因为,为了使用(.|\n)*
,你必须重复*
懒惰(例如(.|\n)*?\[
)。懒惰(即不贪婪)的重复导致大量的回溯,因此它们会损害性能。因此,尽可能使用否定字符类代替惰性重复是最好的。
答案 1 :(得分:1)
您可以在一个正则表达式中完成所有工作,但我认为编写和管理起来非常困难。我可以建议将它拆分为两个不同的正则表达式吗?您可以使用此选项获取索引,下载/上载字段以及不同组中的说明:
\[([1-9]+?)\]\s<\w+?>.+\n\[([\s\S]+?)\]
然后您可以获取包含该消息的组并将其应用于此正则表达式:
Name:\s(.+?)\n[\s\S]*?(Error:|Status:)\s+?(.+?)$
在使用上面的正则表达式之前,请务必在包含该消息的字符串上使用Trim(),否则正则表达式可能无法正常工作。
以下是一些使用正则表达式的C#代码:
Regex regex1 = new Regex("\\[([1-9]+?)\\]\\s<\\w+?>.+\\n\\[([\\s\\S]+?)\\]");
MatchCollection matches = regex1.Matches(logMessage);
foreach (Match match in matches)
{
String indexField = match.Groups[1].Value;
String message = match.Groups[2].Value.Trim();
if (String.IsNullOrEmpty(message) == false)
{
Regex regex2 = new Regex("Name:\\s(.+?)\\n[\\s\\S]*?(Error:|Status:)\\s+?(.+?)$");
Match messageMatch = regex2.Match(message);
String name = messageMatch.Groups[1].Value.Trim();
String statusError = messageMatch.Groups[3].Value.Trim();
}
}
答案 2 :(得分:0)
你可以拿出某事。像自由间隔模式中的以下正则表达式:
~
\[(?<index>\d+)\]\s*
<(?<task>\w+)>(?s).*?
\[(?s).*?
Name:\s*(?<filename>[^\n]+)(?s).*?
(?:Status|Error):\s*(?<status>\d+)(?s).*?
\]
~