Улучшение рабочего регулярного выражения для соответствия нескольким строкам

#php #regex

#php #регулярное выражение

Вопрос:

Я пытаюсь сопоставить пользователей из старого дампа DOS, чтобы их можно было перенести на что-то новое. Они начинаются со % знака и заканчиваются на ] . Некоторые в одной строке, а другие во многих строках.

https://regex101.com/r/0h5ndW/1

Мое регулярное %([^%]*)] выражение работает, но есть ли лучший способ выбрать каждого пользователя, начиная с % до ] (включая % и ] ), чтобы я мог пропустить их preg_replace и манипулировать ими позже?

Я немного скептически отношусь к многострочной части.

Expected Output

 %user:100 [     type=admin,     added=10/12/1997,     last-login:10/20/1997,     total-logins:45,     status:1 ]
%user:111 [     type=user,     added=10/12/1997,     last-login:10/27/1997,     total-logins:145,     status:1 ]
%user:112 [ type=viewer, added=10/12/1997,     last-login:10/23/1997,     total-logins:6,     status:1 ]
%user:113 [ type=viewer, added=10/12/1997,  last-login:10/14/1997,  total-logins:2, status:1]
%user:114 [ type=viewer, added=10/12/1997,  last-login:10/14/1997,  total-logins:1, status:1]
%user:115 [ type=viewer, added=10/12/1997,  last-login:10/12/1997,  total-logins:1, status:1 ]
 

Необработанные данные

 %user:100 [
    type=admin,
    added=10/12/1997,
    last-login:10/20/1997,
    total-logins:45,
    status:1
]

%user:111 [
    type=user,
    added=10/12/1997,
    last-login:10/27/1997,
    total-logins:145,
    status:1
]

%user:112 [ type=viewer, added=10/12/1997,
    last-login:10/23/1997,
    total-logins:6,
    status:1
]

%user:113 [ type=viewer, added=10/12/1997,  last-login:10/14/1997,  total-logins:2, status:1]

%user:114 [ type=viewer, added=10/12/1997,  last-login:10/14/1997,  total-logins:1, 
status:1]

%user:115 [ type=viewer, added=10/12/1997,  last-login:10/12/1997,  total-logins:1, 
status:1
]
 

Ответ №1:

Вы можете использовать это регулярное выражение для поиска:

 ((?:^%|(?!A)G).*)R(?=[^][]*])
 

и замените его на:

 $1
 

Обновленная демонстрация регулярных выражений

PHP-код:

 $repl = preg_replace('/((?:^%|(?!A)G).*)R(?=[^][]*])/m', '$1', $str);
 

Подробности регулярного выражения:

  • ( : Запуск группы захвата # 1
    • (?:^%|(?!A)G) : Сопоставление % в начале строки или перезапуск сопоставления с конца предыдущего сопоставления. G утверждает позицию в конце предыдущего совпадения или в начале строки для первого совпадения.
    • .* : Сопоставьте все в одной строке
  • ) : Завершить группу захвата # 1
  • R : Сопоставление любого символа новой строки
  • (?=[^][]*]) : Убедитесь, что у нас есть ] ahead без сопоставления [ или ] между ними.

Комментарии:

1. Два небольших замечания… ] похоже, что оно не соответствует в RegEx демо и %user:113 вообще не соответствует… Это нормально?

2. Оба желаемых поведения. 1. ] не должен совпадать, потому что мы удаляем новую строку раньше ] . 2. %user:113 не соответствует, потому что он уже находится в одной строке.

Ответ №2:

Другой вариант — использовать вариант шаблона, который вы пробовали с отрицаемым символьным классом, для сопоставления % и от открытия [ до закрытия ] .

Затем для каждого соответствия удаляйте новые строки.

 ^%[^][]*[[^][]*]$
 

Объяснение

  • ^ Начало строки
  • %[^][]* Сопоставьте % и 0 раз с любым символом, отличным от [ или ]
  • [[^][]*] Сопоставление от [ до закрытия ]
  • $ Утверждение конца строки

Демонстрация регулярных выражений | Демонстрация Php

Например

 $result = preg_replace_callback("/^%[^][]*[[^][]*]$/m", function($m) {
    return str_replace(PHP_EOL, "", $m[0]);
}, $data);
 

Ответ №3:

В качестве альтернативы регулярному выражению это просто разделяет данные с помощью ] . Затем обрезает каждую строку и заменяет новые строки (используя PHP_EOL ) пробелом…

 $output = explode("]", $data);
array_pop($output);
array_walk($output, function(amp;$data) {
    $data = str_replace(PHP_EOL, " ", trim($data)."]");
});