Regex удалить определенное число \ n в конце строки

Как удалить максимальное число \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" .

  • OP current regex: выполняется 3 замены, что означает, что все новые строки удалены
  • Мое решение: 1 замена в самом конце строки (таким образом, результат "subject\n » – то, что требуется OP .
  • Регулярное выражение sln из комментариев: 2 заменяются, что даст те же результаты, что и решение 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));