Как удалить максимальное число \n
в конце строки с помощью regex?
Удаление \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 оба результата скрипта, как и ожидалось
Регулярное выражение, чтобы удалить определенное количество строк в конце строки, вам нужно использовать \z
которая соответствует в самом конце строки:
$subject = "\n\n\nsubject\n\n\n"; $count = 2; echo preg_replace("#\n{1,$count}\\z#",null,$subject);
См. Демонстрацию IDEONE
$
Anchor может совпадать с последней строкой в строке, поэтому вы не можете ее использовать. Кроме того, нет смысла сопоставления 0 новых строк для их удаления, поэтому 1
должна быть нижней границей для предельного квантификатора.
Однако вы можете сделать $
match в самом конце строки, используя модификатор /D
( модификатор PCRE_DOLLAR_ENDONLY ):
preg_replace("#\n{1,$count}$#D",null,$subject) ^^^
Ниже приведена соответствующая выдержка из документации PHP PCRE :
Символ доллара (
$
) – это утверждение, которое имеет значение ИСТИНА, только если текущая точка совпадения находится в конце строки субъекта или непосредственно перед символом новой строки, который является последним символом в строке (по умолчанию) . … Значение доллара можно изменить так, чтобы оно соответствовало только самому концу строки , установив параметрPCRE_DOLLAR_ENDONLY
в момент компиляции или сопоставления.
ОТВЕТ НА КОММЕНТАРИИ :
Задача OP состоит в том, чтобы удалить только определенное количество символов новой строки (NOT \r\n
, mixed или \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"
.
"subject\n
» – то, что требуется OP . Давайте сравним, как OP и мои регулярные выражения работают с preg_replace
против preg_replace
"\n\n\nsubject\n\n\n"
:
\n{0,2}$
– первые 2 \n
s найдены, но $
не может утверждать конец строки, а дальнейший откат не находит конца позиции строки -> проверяется следующая позиция. Затем происходит то же самое (снова 2 \n
s не до конца строки). Тогда есть один \n
и s
-> другой сбой, поскольку s
не является концом строки. Затем проверяется s
Это повторяется до тех пор, пока механизм regex не достигнет \n
после t
: two \n
s будут сопоставлены, а $
утвердит позицию в конце строки, но до последней новой строки. Матч , и замена происходит. Затем строка еще не обрабатывается полностью, механизм regex обрабатывает строку и сопоставляет единственную новую строку, которая остается, а $
утверждает позицию в самом конце строки сейчас -> anothe match и replace. И поскольку регулярное выражение только утвердило позицию в конце строки, но не уничтожило ее, а регулярное выражение \n{0,2}$
может соответствовать пустой строке, выполняется операция 3-го совпадения и замены.
\n{1,2}\z
– (MINE) – Найдены первые 2 \n
s, но самый конец позиции строки не был неудачным. Затем повторяется та же ситуация. Затем проверяется \ns
и \n
передает тест (так как \n{1,2}
может соответствовать одному \n
), но тогда нет самого конца строки. Таким образом, двигатель достигает \n
после t
. 2 \n
s сопоставляются, но перед окончательной новой строкой нет конца конца , поэтому у нас есть сбой . Следующий матч будет успешным, потому что есть 2 \n
s, и после них ничего не происходит.
Ведение вещей Простой – это искусство, и это не наука. Простота – легкая (в отличие от тяжелой и тяжелой) … она также бросает вызов логике, поскольку она больше ничего не показывает, чем сама по себе: простота 😉 Код ниже следует за Линией Простоты … и это также хорошо это тоже … однако; не гнусный путь … только простой способ, которым и вы (и машины, как хорошо) понимаете …
<?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));