使用正则表达式解析日志条目为多个部分

3

我有一行文本,它总是相同的(除了结尾的消息):

2021-12-08T18:18:38+00:00 INFO Produktbestand erfolgreich von Collmex abgerufen | "STOCK_AVAILABLE;23;1;363;PCE;-1\r\nMESSAGE;S;204020;Daten?bertragung erfolgreich. Es wurden 1 Datens?tze verarbeitet.\r\n"

我有3个函数应该返回日志条目的一部分:

public function get_log_file_entry_time( string $entry ): string {
    
}

public function get_log_file_entry_level( string $entry ): string {

}

public function get_log_file_entry_message( string $entry ): string {

}

我最初尝试使用空格作为分隔符来使用 explode,这样做虽然可以工作,但不是最好的方式,因为日志消息在某些情况下可能非常长。

我不是正则表达式专家,但我已经找到了以下组合以匹配前两个部分:([^\s]+) ([A-Z]+)

这将返回时间戳和级别。现在我正在努力获取第二组后面的消息-也许我的嵌套根本不完美。任何建议都会让我感到高兴!

注意

消息将从记录级别之后的第一个空格开始。例如:

Produktbestand erfolgreich von Collmex abgerufen | "STOCK_AVAILABLE;23;1;363;PCE;-1\r\nMESSAGE;S;204020;Daten?bertragung erfolgreich. Es wurden 1 Datens?tze verarbeitet.\r\n"


1
如果消息是管道字符之前的部分,那么正则表达式可能是这样的 ^(\S+)\h([A-Z]+)\h([^|]+) https://regex101.com/r/CyMiDJ/1 - The fourth bird
管道是消息的一部分!消息将在日志级别之后开始。 - Mr. Jo
1
所以你想匹配字符串的其余部分,包括换行符?这是唯一的字符串还是有更多格式相同的字符串?匹配字符串的其余部分可以像这样:(?s)^(\S+)\h+([A-Z]+)\h+(.+) https://regex101.com/r/WkuRgY/1 但如果有更多以日期和时间开头的行,它会过度匹配。 - The fourth bird
1
你可以使用类似于 ^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+\d{2}:\d{2})\h+([A-Z]+)\h+(.*(?:\R(?!(?1)).*)*) 的模式来匹配多行 https://regex101.com/r/V8wUYy/1 - The fourth bird
1
制表符是否用作分隔符?还是所有部分都由单个空格分隔?[^\s]更优雅地编写为\S,但如果所有分隔符都是单个空格,则[^ ]也是适当的。 - mickmackusa
显示剩余4条评论
2个回答

5

您可以使用3个捕获组,其中第三个组包含该行的其余内容,后面跟着所有不以日期时间模式开头的行。

您可以使模式对第1组更加具体化,并使用(?1)递归第一个子模式来匹配不以第1组模式开头的其他行。

^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+\d{2}:\d{2})\h+([A-Z]+)\h+(.*(?:\R(?!(?1)).*)*)

部分匹配模式如下:

  • ^ 字符串开始
  • (\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+\d{2}:\d{2}) 捕获第1组,匹配日期和时间格式
  • \h+ 匹配1个或多个水平空格字符
  • ([A-Z]+) 捕获第2组,匹配1个或多个大写字符A-Z
  • \h+ 匹配1个或多个水平空格字符
  • ( 捕获第3组
    • .* 匹配该行的其余部分
    • (?:\R(?!(?1)).*)* 可选地重复匹配换行符和该行的其余部分,并断言当前位置右侧的内容不匹配子模式1(即模式组1)
  • ) 关闭第3组

请参见正则表达式演示PHP演示

例如,有两行文本,都以相同的模式开头:

$re = '/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+\d{2}:\d{2})\h+([A-Z]+)\h+(.*(?:\R(?!(?1)).*)*)/m';
$str = '2021-12-08T18:18:38+00:00 INFO Produktbestand erfolgreich von Collmex abgerufen | "STOCK_AVAILABLE;23;1;363;PCE;-1
MESSAGE;S;204020;Daten?bertragung erfolgreich. Es wurden 1 Datens?tze verarbeitet.
"
2021-12-08T18:18:38+00:00 INFO Produktbestand erfolgreich von Collmex abgerufen | "STOCK_AVAILABLE;23;1;363;PCE;-1
MESSAGE;S;204020;Daten?bertragung erfolgreich. Es wurden 1 Datens?tze verarbeitet.
"';

preg_match_all($re, $str, $matches, PREG_SET_ORDER);

foreach ($matches as $match) {
    print_r($match);
}

输出

Array
(
    [0] => 2021-12-08T18:18:38+00:00 INFO Produktbestand erfolgreich von Collmex abgerufen | "STOCK_AVAILABLE;23;1;363;PCE;-1
MESSAGE;S;204020;Daten?bertragung erfolgreich. Es wurden 1 Datens?tze verarbeitet.
"
    [1] => 2021-12-08T18:18:38+00:00
    [2] => INFO
    [3] => Produktbestand erfolgreich von Collmex abgerufen | "STOCK_AVAILABLE;23;1;363;PCE;-1
MESSAGE;S;204020;Daten?bertragung erfolgreich. Es wurden 1 Datens?tze verarbeitet.
"
)
Array
(
    [0] => 2021-12-08T18:18:38+00:00 INFO Produktbestand erfolgreich von Collmex abgerufen | "STOCK_AVAILABLE;23;1;363;PCE;-1
MESSAGE;S;204020;Daten?bertragung erfolgreich. Es wurden 1 Datens?tze verarbeitet.
"
    [1] => 2021-12-08T18:18:38+00:00
    [2] => INFO
    [3] => Produktbestand erfolgreich von Collmex abgerufen | "STOCK_AVAILABLE;23;1;363;PCE;-1
MESSAGE;S;204020;Daten?bertragung erfolgreich. Es wurden 1 Datens?tze verarbeitet.
"
)

2
这里有一个简单的方法,使用explode()和它的限制参数。请看下面的示例:
list($date, $severity, $message) = explode(' ', $str, 3);

var_dump($date, $severity, $message);
/*
string(25) "2021-12-08T18:18:38+00:00"
string(4) "INFO"
string(170) "Produktbestand erfolgreich von Collmex abgerufen | "STOCK_AVAILABLE;23;1;363;PCE;-1 MESSAGE;S;204020;Daten?bertragung erfolgreich. Es wurden 1 Datens?tze verarbeitet.""
*/

只要消息前面的空格是恒定的,且在其之前的任何部分都不包含空格,这种方法就可行。如果消息前面的任何部分有时包含空格,则此方法将无法保持一致性。

1
喜欢这个想法!由于未来可能会添加一些空格,因此我会选择正则表达式,但从目前的角度来看,这真是太棒了! - Mr. Jo
空格会如何破坏这种干净、直接的技术? - mickmackusa
1
@mickmackusa 只有前两个字段中的额外空格可能会影响它。例如:日期信息这里是一条消息(好的),但如果第二个“字段”可能超过2个单词,比如日期信息额外这里是另一条消息,那么第三个字段将与消息组合在一起。正则表达式可以选择捕获中间部分,或者如果不匹配就失败,而这将始终返回某些内容,但每个元素可能不符合预期,如果引入了额外的空格。 - drew010
那么你的问题中没有表达出你的项目数据的复杂性? - mickmackusa
@mickmackusa 我谈论的是未来可能使用的想法,但我的问题反映了当前状态,而不仅仅是想法。 - Mr. Jo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接