【问题标题】:Matching a substring of any length and characters using RegEx使用 RegEx 匹配任意长度和字符的子字符串
【发布时间】:2012-05-18 14:35:03
【问题描述】:

我希望能够使用 c# 中的正则表达式匹配并提取以下字符串中的所有子字符串:

"2012-05-15 00:49:02 192.168.100.10 POST /Microsoft-Server-ActiveSync/default.eas User=nikced&DeviceId=ApplDNWGRKZQDTC0&DeviceType=iPhone&Cmd=Ping&Log=V121_Sst8_LdapC0_LdapL0_RpcC31_RpcL50_Hb3540_Erq1_Pk1728465481_S2_ 443 redcloud\nikced 94.234.170.42 Apple-iPhone4C1/902.179 200 0 64 3140491"

由于它是一个日志文件,因此正则表达式应该能够处理任何类似类型的行。

在这种情况下,集合的首选输出应该是:

2012-05-15
00:49:02
192.168.100.10
/Microsoft-Server-ActiveSync/default.eas
User=nikced&DeviceId=ApplDNWGRKZQDTC0&DeviceType=iPhone&Cmd=Ping&Log=V121_Sst8_LdapC0_LdapL0_RpcC31_RpcL50_Hb3540_Erq1_Pk1728465481_S2_
443
redcloud\nikced
94.234.170.42
Apple-iPhone4C1/902.179
200
0
64
3140491

感谢使用 C#、.net 和正则表达式将上述子字符串提取到集合中的任何答案(首选 MatchCollection)。所有日志行都遵循相同的格式和模式。

【问题讨论】:

  • 使用 C# RegEx 有什么困难?除了“懒得自己做”?
  • 我知道已经有了答案,但我对你已经尝试过的东西很感兴趣......

标签: c# .net regex substring


【解决方案1】:

非常复杂的正则表达式传入:

logFile.Split(' ');

【讨论】:

  • KooKiz:你能给我解释一下吗?它有点复杂,我不太明白它是如何工作的...... ;-)
  • 我可能应该包括我需要一个不使用明显空间分割的解决方案,对此感到抱歉。
  • @NIklas Persson:那么您应该指定您的确切要求/约束​​是什么。您不能在纯空间上拆分这一事实也可能会影响任何潜在的正则表达式解决方案。
  • 正如 LukeH 所说,我们需要了解为什么禁止在空格上分割。您说所有日志行都遵循相同的格式和模式,但可能某些记录中的空格不同?请问完整的故事是什么?
  • @NIklasPersson 您的子字符串是如何定义的, 如果不是空格?您的示例数据显示子字符串由空格分隔,但您对给定答案的反对意味着有一些更微妙的定义在起作用。在任何人回答这个问题之前,你必须想出逻辑来回答“什么是子字符串?”这个问题
【解决方案2】:

这将为您提供一个数组,您可以遍历该数组以检索由空格分隔的所有“行”

string[] lines = log.Split(' ');

【讨论】:

  • 我不能在 ' ' 上使用拆分,我需要在没有拆分的情况下提取单独的字段,这有点棘手。查找日期、时间和 ip 很容易,因为我可以匹配以下内容:\d+\-\d+\-\d+ \d+\:\d+\:\d+ \d+\.\d+\.\d+\.\d+
【解决方案3】:

您不需要使用正则表达式。您可以简单地使用String.Split Method,并指定空格作为分隔符:

  string [] substrings = line.Split(new Char [] {' '});

如果您需要识别每个部分的种类,那么您应该指定您需要查找的内容,并且可以为其创建一个正则表达式。

无论如何,如果您真的想使用正则表达式,请执行以下操作:

  Regex re = new Regex (@"(?:(?<s>[^ ]+)(?: |$))*");

当您调用 Match 方法时,这将为您提供“s”组中的所有捕获。

正如 OP 在评论中指出的那样,分隔符可以是来自单个空格的任何东西,那么可能的分隔符应该包含在表达式的 (?: |$)[^ ] 部分中。 IE。如果空格和制表符都是可能的分隔符,则将该部分替换为(?: |\t|$)[^ \t]。如果您需要接受多个这些字符作为分隔符,请在 () 组之后添加 +

  (?:(?<s>[^ \t]+)(?: |\t|$)+)*

【讨论】:

    【解决方案4】:

    最快最明显的方法是使用String.Split

    string[] substrings = result = line->Split( nullptr, StringSplitOptions::RemoveEmptyEntries );
    

    但是,如果您坚持使用 MatchCollection,那么这将满足您的需求

    MatchCollection ^ substrings = Regex.Matches(line, "\\S+")
    

    【讨论】:

    • 我需要检查大量的日志文件并识别、匹配和提取不同的子字符串到字段中,以便找到真正重要的子字符串。由于日志文件可能包含大量非重要信息,有时甚至是不规则信息,因此我需要正则表达式来匹配感兴趣的信息。
    • 啊啊!然后,您在展示更直接的方法太慢之前进行优化。正则表达式将比简单的 String.Split 慢,您应该首先以这种方式生成 all 字段并忽略不需要的字段。
    • 也许另一种可能是,如果日志文件有固定宽度的字段,您可以简单地在硬编码位置提取子字符串?
    【解决方案5】:

    真的,你只需要把它分解成几个部分。

    首先,日期。它会一直是 YYYY-MM-DD 格式吗?会不会因地区/文化设置而有所不同?

    (?<LogDate>dddd-dd-dd)
    

    接下来,你有时间。一样的:

    (?<LogTime>dd:dd:dd)
    

    接下来,我假设这是实际调用的 Web 方法?不完全确定,因为您还没有真正解释数据的布局方式。但是,我假设它要么是 POST 要么是 GET,所以这就是我们接下来要做的......

    (?<LogMethod>POST|GET)
    

    只需对您感兴趣的日志行的每个部分执行此操作,您就可以完成设置。即:

    (?<LogDate>dddd-dd-dd) (?<LogTime>dd:dd:dd) (?<LogMethod>POST|GET)...
    

    如果你想锚定到行的开头/结尾,请务必分别使用 ^ 和 $。当您获取匹配项时,您可以通过使用命名组(例如match.Groups["LogMethod"].Value)索引 Groups 属性来获取每个组的值。祝你好运!

    【讨论】:

    • 这是我想要实现的,但我如何提取/匹配以下部分及其之后的部分:/Microsoft-Server-ActiveSync/default.eas User=nikced&DeviceId=ApplDNWGRKZQDTC0&DeviceType=iPhone&Cmd=Ping&Log =V121_Sst8_LdapC0_LdapL0_RpcC31_RpcL50_Hb3540_Erq1_Pk1728465481_S2_
    • 此解决方案假定示例日志记录中指示的位置存在空格,但我们现在了解到情况可能并非如此。
    • @NIklas Persson:\S+ 的简单正则表达式将匹配该字符串,但我们可以假设它不包含空格吗?请解释一下空格的处理方式。
    猜你喜欢
    • 2011-12-22
    • 2014-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-10
    • 1970-01-01
    相关资源
    最近更新 更多