【问题标题】:Regex - Get all text after pattern from log C#正则表达式 - 从日志 C# 中获取模式后的所有文本
【发布时间】:2015-08-18 08:45:30
【问题描述】:

我想用 C# 解析以下日志文​​件。

我已经走上了使用 RegEx 将大部分内容拆分的路线。 我已经在 RegExr 中测试了这个,并检查了 MultiLine (m) 标志。

日志

5376:0084 2015-08-07 13:51:29.103 Error ### Error Message ###
5376:0084 2015-08-07 13:51:35.545 Error Discarding invalid session
    System.Web.Services.Protocols.SoapException: Verify Session ID failed
    at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
    at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
5376:0084 2015-08-07 13:51:36.013 Error ### Error Message ###

分表:

| ProcessID | DateTime                | Type  | Message               |
|-----------|-------------------------|-------|-----------------------|
| 5376:0084 | 2015-08-07 13:51:29.103 | Error | ### Error Message ### |

我使用了以下模式

string pattern = @"(.*:\d{4}) ((\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2}).(\d{3})) ([A-Za-z\n]+) (.*$)";

这得到第 1,3 和 6 行,但我想将第 2-5 行收集到一组中。 所以 "Discarding ... parameters)" 将是整个消息。

【问题讨论】:

  • 请说明您需要对问题本身有什么不同。

标签: c# regex parsing logging


【解决方案1】:

请注意,在日志解析中命名捕获非常有用,我强烈建议使用它们。此外,您可以使用内联单行修饰符 (?s:...) 更好地控制使用 . 捕获的内容。这样,您不必使用全局 RegexOptions.Singleline 选项,您仍然可以使用 . 匹配除换行符以外的任何符号。

这是我的尝试:

var pattern = @"(?m)^(?<ProcessID>\d{4}:\d{4})\s+(?<DTime>\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\.\d+)\s+(?<Type>\w+)\s+(?<Message>(?s:.*?(?=\n\d+:\d+|\r?\z)))";

这里,(?m)^ 设置了多行模式以匹配行开头,然后我修改了 ID 和日期时间子模式以使用\d{n} 更高效,Type 部分实际上可以调整为您的需要(例如[\w\s]+),而Message部分将只匹配任意数量的字符,直到新行上的XXX:XXXX(由于\n\d+:\d+)或直到字符串的末尾(\z )。 见regex demo,见表格标签。

【讨论】:

  • 谢谢,我喜欢“命名捕获”这个想法,这将使我的代码更有意义
【解决方案2】:

您还需要匹配Message 中存在的换行符 部分。这可以通过使用 DOTALL 修饰符 s 来实现。

@"(?s)(\d+:\d{4}) (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}) ([A-Za-z\n]+) (.*?)(?=\n\d+:|$)"

@"(?s)(?:\n|^)(\d+:\d{4}) (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}) ([A-Za-z\n]+) (.*?)(?=\n\d+:|$)"

DEMO

【讨论】:

  • 谢谢,我可以从第 0 组中删除第 1-10 组来获得差异吗?
  • 是的,请参阅演示链接。四个捕获组就足够了。
  • 只有 5 个组,在使用此正则表达式的匹配结果中从 0 到 4 索引。那时你不能删除 10 个组。
  • 是的,我排除了第 0 组(包含所有匹配的字符)。
  • @AvinashRaj:开个玩笑。第 0 组不能被“排除”,如果是,则意味着不匹配。 :) 另外,在 C# 中有一个 singleline 标志/修饰符,而不是 DOTALL
【解决方案3】:

亚历克斯。试试这个:

string pattern = @"^(\S+) (\S+ \S+) (\S+) ((?:.*(?:\n\s)?)+)";

(示例在这里:https://regex101.com/r/uI4uQ0/1

  1. (\S+) = "5376:0084";
  2. (\S+ \S+) = "2015-08-07 13:51:29.103"
  3. (\S+) = “错误”(仅一个字)
  4. ((?:.*(?:\n\s)?)+) = "...会话
    系统...
    在……”

Magick 在这里:“\n\s”。它说我们需要换行符和任何空白字符。

祝你好运,迈克。

【讨论】:

    【解决方案4】:

    除了正则表达式,对于解析日志文件,您还可以使用TextFieldParser 类。虽然这是一个不必要的依赖这个组件Microsoft.VisualBasic.FileIO.TextFieldParser,但它是一个很好的。

    这里有一个good tutorial,关于如何使用这个类。

    【讨论】:

    • 这无济于事,因为其中一个字段包含换行符。
    • @stribizhev,也许使用 Environment.NewLine 与此处使用 vbTab 的方式相同:reader.Delimiters = New String() {"," , vbTab}
    • 根据我的经验,我无法使用 TextFieldParser 正确处理带有换行符的条目,我必须执行彻底的预处理。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多