Страницы

Поиск по вопросам

суббота, 15 июня 2019 г.

Неожиданное поведение preg_replace()

Есть задача удалить из текста последний перевод строки
, если за ним нет символов, либо его же и пробелы следующие за ним, если кроме пробелов до конца текста нет других символов.
Использую preg_replace() и регулярное выражение %
\x20*$%
Тест выдающий ожидаемое поведение при замене:
$text = "abcd

"; var_dump(preg_replace('%
\x20*$%', '', $text, -1, $count), $count); var_dump(preg_replace('%
\x20*$%', '', $text, 1, $count), $count);
Результат работы:
string 'abcd ' (length=10) int 1
string 'abcd ' (length=10) int 1
Тест выдающий неожиданный результат:
$text = "abcd

"; var_dump(preg_replace('%
\x20*$%', '', $text, -1, $count), $count); var_dump(preg_replace('%
\x20*$%', '', $text, 1, $count), $count);
Результат работы:
string 'abcd' (length=4) <== замена прошла два раза, int 2 <== вместо одного как ожидалось
string 'abcd ' (length=5) <== "съежены" пробелы до символа перевода строки, int 1 <== даже при выполнении всего 1ой замены
Вопрос: В чем моя ошибка?
P.S. Аналогичное регулярное выражение для начала текста работает как ожидалось во всех случаях.


Ответ

По умолчанию, PCRE обрабатывает данные как однострочную символьную строку (даже если она содержит несколько разделителей строк). Метасимвол начала строки '^' соответствует только началу обрабатываемого текста, в то время как метасимвол "конец строки" '$' соответствует концу текста, либо позиции перед завершающим текст переводом строки (в случае, если модификатор D не установлен).
Т.е. $ трактуется как конец строки ПЕРЕД
, если он является последним символом.
В вашем случае надо использовать модификатор D
$text = "abcd

"; var_dump(preg_replace('%
\x20*$%D', '', $text, -1, $count), $count); var_dump(preg_replace('%
\x20*$%D', '', $text, 1, $count), $count);
string(10) "abcd " int(1) string(10) "abcd " int(1)

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

Отправить комментарий