正则表达式删除字符串末尾的一定数量的\ n

时间:2016-08-20 13:56:57

标签: php regex

如何使用正则表达式删除字符串末尾的\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时,两个脚本都按预期结果

2 个答案:

答案 0 :(得分:1)

要在字符串末尾删除一些特定数量的换行符的正则表达式,您需要使用匹配在字符串末尾的\z锚点:

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

请参阅IDEONE demo

$锚点可能会在字符串的最后一个换行符处匹配,因此您无法使用它。此外,没有必要匹配0个换行符来删除它们,因此,1应该是限制量词的下限。

但是,您可以使用$修饰符( PCRE_DOLLAR_ENDONLY修饰符)在字符串的最后匹配/D

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

以下是PHP PCRE documentation的一些相关摘录:

  

美元字符($)是一个断言,只有当前匹配点位于主题字符串的末尾 或之前, TRUE 换行符是字符串中的最后一个字符(默认情况下) 。   ...   通过在编译或匹配时设置PCRE_DOLLAR_ENDONLY选项,可以更改美元的含义,使其仅在字符串的最后匹配。 / p>

回答评论

问题OP 仅在字符串末尾删除特定数量的换行符号(NOT \r\n,混合\r\r\n。注意,不是在最后一个非换行符之后,而是在字符串的末尾。现在让我们测试当前的解决方案(参见the demo code)。请注意,下面的代码不会删除换行符,而是替换为文字\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个(或者如果没有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,但$无法断言字符串的结尾,并且进一步的回溯未找到字符串位置的结尾 - &gt ;检查下一个位置。然后发生同样的事情(再次2 \n s不在字符串结束之前)。然后有一个\ns - >另一个失败,因为s不是字符串的结尾。然后测试s这将重复,直到正则表达式引擎在\n之后到达t:两个\n匹配,并且$断言位置字符串的结尾但在最后一行之前。 匹配,并进行替换。然后,字符串尚未完全解析,正则表达式引擎处理字符串,并匹配剩余的单个换行符,$现在断言字符串最末端的位置 - >其他匹配和替换发生。由于正则表达式只在字符串末尾声明了位置,但没有使用它,并且正则表达式\n{0,2}$可以匹配空字符串,因此存在第3个匹配并替换操作。

  • \n{1,2}\z - (MINE) - 找到前2个\n但字符串位置的最后一个不是,失败。然后重复相同的情况。然后检查\ns\n通过测试(因为\n{1,2}可以匹配一个\n),但是没有字符串的结尾。这样,引擎在\n之后达到t。 2个\n匹配,但在最终换行符之前没有字符串的最后一端,因此我们在这里失败了。下一场比赛是成功的,因为有两个\n并且没有任何内容。

答案 1 :(得分:-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));