【问题标题】:preg_split on regex line startpreg_split 在正则表达式行开始
【发布时间】:2020-08-10 05:09:17
【问题描述】:

我正在尝试格式化以下文件;

[30-05-2013 15:45:54] A A
[26-06-2013 14:44:44] B A
[26-06-2013 14:44:44] C A
[26-06-2013 14:43:16] Some lines are so large, they take multiple lines, so explode('\n') won't work because
I need the complete message
[26-06-2013 14:44:44] E A
[26-06-2013 14:44:44] F A
[26-06-2013 14:44:44] G A

预期输出:

Array
(
    [0] => [30-05-2013 15:45:54] A A
    [1] => [26-06-2013 14:44:44] B A
    [2] => [26-06-2013 14:44:44] C A
    [3] => [26-06-2013 14:43:16] Some lines are so large, they take multiple lines, so 
            explode('\n') won't work because
            I need the complete message
    [4] => [26-06-2013 14:44:44] E A
    ...
)


基于How do I include the split delimiter in results for preg_split()?,我尝试使用积极的后视来保留时间戳并提出Regex101
(?<=\[)(.+)(?<=\])(.+)

在以下PHP代码中使用;

#!/usr/bin/env php
<?php

    class Chat {

        function __construct() {

            // Read chat file
            $this->f = file_get_contents(__DIR__ . '/testchat.txt');

            // Split on '[\d]'
            $r = "/(?<=\[)(.+)(?<=\])(.+)/";
            $l = preg_split($r, $this->f, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);

            var_dump(count($l));
            var_dump($l);
        }
    }
$c = new Chat();

这给了我以下输出;

array(22) {
  [0]=>
  string(1) "["
  [1]=>
  string(20) "30-05-2013 15:45:54]"
  [2]=>
  string(4) " A A"
  [3]=>
  string(2) "
["
  [4]=>
  string(20) "26-06-2013 14:44:44]"
  [5]=>
  string(4) " B A"
  [6]=>
  string(2) "
["
  [7]=>
  string(20) "26-06-2013 14:44:44]"
  [8]=>
  string(4) " C A"
  [9]=>
  string(2) "
["
  [10]=>
  string(20) "26-06-2013 14:43:16]"
  [11]=>
  string(87) " Some lines are so large, they take multiple lines, so explode('\n') won't work because"
  [12]=>
  string(30) "
I need the complete message
["

问题

  1. 为什么第一个 [ 会被忽略?
  2. 我应该如何更改正则表达式以获得所需的输出?
  3. 为什么会有带有PREG_SPLIT_NO_EMPTY 的空字符串?

【问题讨论】:

  • this 是否适合您 - (\[.*?\])([^\[]+)

标签: php regex preg-split


【解决方案1】:

preg_split,你可以使用

'~\R+(?=\[\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2}])~'

regex demo

详情

  • \R+ - 1+ 换行符
  • (?=\[\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2}]) - 一个积极的前瞻,在当前位置的右侧,需要
    • \[ - 一个 [ 字符
    • \d{2}-\d{2}-\d{4} - 类似日期的模式,2 位数字,连字符,2 位数字,连字符和 2 位数字
    • - 一个空格
    • \d{2}:\d{2}:\d{2}] - 类时间模式,2 位,:,2 位,:,2 位。

PHP 演示:

$text = "[30-05-2013 15:45:54] A A
[26-06-2013 14:44:44] B A
[26-06-2013 14:44:44] C A
[26-06-2013 14:43:16] Some lines are so large, they take multiple lines, so explode('\n') won't work because
I need the complete message
[26-06-2013 14:44:44] E A
[26-06-2013 14:44:44] F A
[26-06-2013 14:44:44] G A";

print_r(preg_split('~\R+(?=\[\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2}])~', $text));

输出:

Array
(
    [0] => [30-05-2013 15:45:54] A A
    [1] => [26-06-2013 14:44:44] B A
    [2] => [26-06-2013 14:44:44] C A
    [3] => [26-06-2013 14:43:16] Some lines are so large, they take multiple lines, so explode('
') won't work because
I need the complete message
    [4] => [26-06-2013 14:44:44] E A
    [5] => [26-06-2013 14:44:44] F A
    [6] => [26-06-2013 14:44:44] G A
)

如果您需要获取更多详细信息而不仅仅是拆分,您可以使用 matching 方法与

'~^\[(\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2})]\s*+(.*?)(?=\s*^\[(?1)]|\z)~ms'

the regex demo,把它当做

preg_match_all('~^\[(\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2})]\s*+(.*?)(?=\s*^\[(?1)]|\z)~ms', $text, $matches)

会匹配

  • ^ - 行首
  • \[(\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2})] - 日期时间详细信息(捕获到第 1 组)
  • \s*+ - 0+ 个空格(可能)
  • (.*?) - 尽可能少的任何 0+ 个字符,直到第一次出现
  • (?=\s*^\[(?1)]|\z) - 前瞻匹配紧随其后的位置
    • \s* - 0+ 个空格
    • ^ - 行首
    • \[(?1)] - [,第 1 组模式,]
    • | - 或
    • \z - 字符串的最后。

【讨论】:

  • 完美!非常感谢您的详细信息!您是否碰巧知道是否可以将日期和文本拆分为数组? [0] =&gt; [ '[30-...]', 'A A' ]
  • @0stone0 我想我刚刚回答了这个问题。只是觉得你会需要那个。
  • @0stone0 我想出了第二个正则表达式的更高效版本,'~^\[(\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2})]\h*+(.*(?:\R(?!\[(?1)]).*)*)~m',参见here
  • 非常适合提高速度!谢谢!
【解决方案2】:

迟到的答案,但您也可以使用:

$text =  file_get_contents("testchat.txt");

preg_match_all('/(\[.*?\])([^\[]+)/im', $text, $matches, PREG_PATTERN_ORDER);
for ($i = 0; $i < count($matches[0]); $i++) {
    $date = $matches[1][$i];
    $line = $matches[2][$i];
    print("$date $line");
}

【讨论】:

  • 此方案存在一个潜在问题,即如果时间戳后面的文本可以包含[,则会过早停止或拆分过多,请参阅demo
猜你喜欢
  • 2019-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多