preg_split при запуске строки регулярного выражения - PullRequest
1 голос
/ 26 апреля 2020

Я пытаюсь отформатировать следующий файл;

[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
    ...
)


На основе Как включить разделитель в результаты для 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?

Ответы [ 2 ]

2 голосов
/ 26 апреля 2020

С preg_split вы можете использовать

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

См. Демо regex

Подробности

  • \R+ - 1+ символов разрыва строки
  • (?=\[\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2}]) - положительный прогноз, который, непосредственно справа от текущего местоположения, требует
    • \[ - [ char
    • \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
)

На всякий случай, если вам нужно получить больше деталей, чем просто разделение, вы можете использовать соответствующий подход с

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

См. 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 голосов
/ 26 апреля 2020

Поздний ответ, но вы также можете использовать:

$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");
}
...