Регулярное выражение для удаления определенного числа \ n в конце строки

php regex

87 просмотра

2 ответа

Как удалить максимальное количество \nв конце строки с помощью регулярных выражений?

\nУдаление , как ожидается , при поиске позиции в начале строки ^, но я не могу иметь правильный результат при поиске позиции в конце строки.

$subject = "\n\n\nsubject\n\n\n";
# maximum removal
$count = 2;

# expect maximum 2 LF removed, 2 removed
var_dump(preg_replace("#^\\n{0,$count}#",null,$subject));

# expect maximum 2 LF removed, 3 removed
var_dump(preg_replace("#\\n{0,$count}\$#",null,$subject));

однако при использовании \ r оба сценария дают ожидаемый результат

Автор: Andikac Источник Размещён: 08.11.2019 11:23

Ответы (2)


1 плюс

Решение

Регулярное выражение для удаления определенного количества новых строк в конце строки, вам нужно использовать \zпривязку, совпадающую в самом конце строки:

$subject = "\n\n\nsubject\n\n\n";
$count = 2;
echo preg_replace("#\n{1,$count}\\z#",null,$subject);

Посмотреть демоверсию IDEONE

$Анкер может соответствовать на завершающей новой строке в строке, таким образом, вы не можете использовать его. Также нет точки, совпадающей с 0 новыми строками, чтобы удалить их, поэтому 1должна быть нижняя граница для ограничивающего квантификатора.

Однако вы можете сделать $совпадение в самом конце строки, используя /Dмодификатор ( PCRE_DOLLAR_ENDONLY модификатор ):

preg_replace("#\n{1,$count}$#D",null,$subject)
                           ^^^

Вот некоторые соответствующие выдержки из документации PHP PCRE :

Символ доллара ( $) является утверждением, которое имеет значение ИСТИНА, только если текущая совпадающая точка находится в конце строки темы или непосредственно перед символом новой строки, который является последним символом в строке (по умолчанию) . ... Значение доллара можно изменить так, чтобы оно совпадало только в самом конце строки , установив PCRE_DOLLAR_ENDONLYпараметр во время компиляции или сопоставления.

ОТВЕТ НА КОММЕНТАРИИ :

Задача OP состоит в том, чтобы удалить только определенное количество символов новой строки (НЕ \r\n, ни смешанных, \rни \r\n) в конце строки . Обратите внимание, что не после последнего символа перевода строки, но в конце строки. Давайте теперь протестируем текущие решения (см. Демонстрационный код ). Обратите внимание, что приведенный ниже код не удаляет символы новой строки, он заменяет буквальную \nпоследовательность, чтобы увидеть, что на самом деле было заменено.

$subject = "subject\n\n\n";
$count = 2;
echo preg_replace("#\\n{0,$count}\$#","\\n",$subject); // OP - "subject\n\n\n"
echo '"'.preg_replace("#\n{1,$count}\\z#","\\n",$subject).'"'; // mine removes 2 at the end:
//"subject
//\n"
echo '"'.preg_replace("#(?:\r?\n){1,$count}$#","\\n",$subject).'"';//sln's - "subject\n\n"

Итак, здесь нам нужно удалить 2 (или 1, если нет 2) символов новой строки в конце строки, которая имеет 3 символа новой строки. Это означает, что ожидаемый результат есть "subject\n".

  • OP текущее регулярное выражение: выполнено 3 замены, что означает, что все новые строки удалены
  • Мое решение: 1 замена в самом конце строки (таким образом, результат "subject\n"- то, что нужно OP .
  • регулярное выражение sln из комментариев: выполняется 2 замены, которые дают те же результаты, что и решение OP.

Давайте сравним , как OP и мои регулярные выражения работают с preg_replaceпротив "\n\n\nsubject\n\n\n"строки:

  • \n{0,2}$- первые 2 \nс найдены, но $не могут подтвердить конец строки, а дальнейший обратный отслеживание не находит конца строки -> проверяется следующая позиция. Затем происходит то же самое (снова за 2 \nс до конца строки). Тогда есть один \nи s-> другой сбой, так как sэто не конец строки. Затем sпроверяется. Это повторяется до тех пор, пока механизм регулярных выражений не достигнет \nпосле t: два \ns сопоставляются, и $утверждается позиция в конце строки, но перед последним переводом строки. Матч , и замена происходит. Затем строка еще не проанализирована полностью, механизм регулярных выражений обрабатывает строку и соответствует единственной оставшейся строке перевода, и$устанавливает позицию в самом конце строки -> другое совпадение и замена происходит. И так как регулярное выражение только утверждало позицию в конце строки, но не использовало ее, и регулярное выражение \n{0,2}$может соответствовать пустой строке, существует 3-я операция сравнения и замены.

  • \n{1,2}\z- (MINE) - первые 2 \nс найдены, но самого конца строки не было, ошибка. Затем та же самая ситуация повторяется. Затем \nsпроверяется и \nпроходит тест (так как \n{1,2}может соответствовать одному \n), но тогда нет самого конца строки. Таким образом, двигатель достигает \nпосле t. 2 \nсовпадают, но перед последней строкой нет самого конца строки, таким образом, у нас есть ошибка здесь . Следующий матч удался, потому что есть 2 \nс и после них ничего нет.

Автор: Wiktor Stribiżew Размещён: 20.08.2016 03:11

-1 плюса

Сохранять вещи простыми - это искусство и никогда не будет наукой. Простота легка (в отличие от тяжелой и веской) ... она также не поддается логике, так как в ней НИЧЕГО не видно, кроме самого себя: Простота ;-) Приведенный ниже код следует линии простоты ... и точно так же это тоже ... однако; не отвратительный способ ... только простой способ, который понимают и вы (и машины) ...

<?php

    $subject    = "\n\n\nsubject\n\n\n";
    $count      = 2;

    # EXPECTS 2 LF REMOVED AND SURE ENOUGH: ONLY 2 REMOVED...
    var_dump(preg_replace("#^\n{" . $count . "}#",null,$subject));

    # EXPECTS 2 LF REMOVED AND AGAIN, INDEED: ONLY 2 REMOVED...
    var_dump(preg_replace("#\n{" . $count . "}\$#",null,$subject));
Автор: Poiz Размещён: 20.08.2016 02:30
Вопросы из категории :
32x32