【问题标题】:Parse log entry with regex into multiple piecesPHP:使用正则表达式将日志条目解析为多个部分
【发布时间】:2022-01-13 20:06:58
【问题描述】:

我需要一些帮助,因为我不是 PHP RegEx 专家。我这里有这行文字,总是一样的(除了最后的信息):

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,这虽然有效,但不是最好的方法,因为在某些情况下日志消息可能很长。

我不是 RegEx 专家,但我找到了以下组合来匹配前两个部分:([^\s]+) ([A-Z]+)

这将返回时间戳和级别。现在我很难在第二组之后得到消息 - 也许我的嵌套根本不完美。任何建议都会让我开心!

通知

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

Produktbestand erfolgreich von Collmex abgerufen | "STOCK_AVAILABLE;23;1;363;PCE;-1\r\nMESSAGE;S;204020;日期?bertragung 埃尔福格雷希。 Es wurden 1 Datens?tze verarbeitet.\r\n"

【问题讨论】:

  • 如果消息是管道字符之前的部分,那么可能像这样^(\S+)\h([A-Z]+)\h([^|]+)regex101.com/r/CyMiDJ/1
  • 管道是消息的一部分!该消息将在日志级别之后开始。
  • 所以你想匹配字符串的其余部分,包括换行符?这是唯一的字符串还是有更多具有相同格式的字符串?匹配字符串的其余部分可以像这样(?s)^(\S+)\h+([A-Z]+)\h+(.+)regex101.com/r/WkuRgY/1,但如果有更多行以日期和时间开头,它将过度匹配。
  • 您可以使用^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+\d{2}:\d{2})\h+([A-Z]+)\h+(.*(?:\R(?!(?1)).*)*) 之类的模式用于多行regex101.com/r/V8wUYy/1
  • 制表符是否用作分隔符?还是所有部分都由一个空格分隔? [^\s] 写成\S 更优雅,但如果所有分隔符都是单个空格,那么[^ ] 也是合适的。

标签: php regex


【解决方案1】:

您可以使用 3 个捕获组,其中第 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})捕获group 1,匹配日期和时间,如模式
  • \h+ 匹配 1+ 个水平空白字符
  • ([A-Z]+) 捕获组 2,匹配 1+ 个大写字符 A-Z
  • \h+ 匹配 1+ 个水平空白字符
  • ( 捕获第 3 组
    • .*匹配其余行
    • (?:\R(?!(?1)).*)* 可选地重复匹配换行符和行的其余部分,断言从当前位置直接向右的内容与子模式 1(模式组 1)不匹配
  • )关闭第三组

查看regex demoPHP demo

例如有 2 行,都以相同的模式开始:

$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.""
    */
    

    只要消息之前的空格是不变的,并且导致它的任何部分都不能包含空格,这将起作用。如果消息之前的任何部分有时有空格,那么这将无法始终如一地工作。

    【讨论】:

    • 喜欢这个主意!由于以后可能会添加一些空格,所以我会选择正则表达式,但从目前的角度来看,这是天才!
    • 空白会如何破坏这种干净、直接的技术?
    • @mickmackusa 只有前 2 个字段中的额外空格会影响它。例如:DATE INFO Here is a message(好),但如果第二个“字段”可能超过 2 个单词,如 DATE INFO EXTRA Here is another message,那么第三个字段将与消息组合。正则表达式可以选择捕获中间,如果不匹配则失败,而这总是会返回一些东西,但如果引入额外的空格,每个元素可能与预期不匹配。
    • 所以您没有在问题中表示项目数据的复杂性?
    • @mickmackusa 我说的是未来可能会用到的想法,但我的问题反映的是当前状态,而不仅仅是想法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-08
    相关资源
    最近更新 更多