Java 替换文本末尾的额外字符

Java 替换文本末尾的额外字符,java,php,regex,pcre,Java,Php,Regex,Pcre,在PHP和Java中,我对‍‍‍-A-我得到了*A**。我应用了对称模式,得到了一个不对称的结果!为什么?我想知道为什么它的输出不是*A* 模式说除了字符串末尾的字母以外的所有东西都应该替换为*,它也是贪婪的,应该一起替换所有非字母的东西 在RegexBuddy中,我得到了一个*,这就是我所期望的 更新:我简化了问题,以集中我的主要关注点 正确的正则表达式如下所示: $arr = preg_replace('#^[^\pL]+|[^\pL]+$#','*', array(

在PHP和Java中,我对‍‍‍<代码>-A-我得到了
*A**
。我应用了对称模式,得到了一个不对称的结果!为什么?我想知道为什么它的输出不是
*A*

模式说除了字符串末尾的字母以外的所有东西都应该替换为
*
,它也是贪婪的,应该一起替换所有非字母的东西

在RegexBuddy中,我得到了一个*,这就是我所期望的


更新:我简化了问题,以集中我的主要关注点

正确的正则表达式如下所示:

$arr = preg_replace('#^[^\pL]+|[^\pL]+$#','*', 
           array('A','-A-','---A---','-+*A*+-','------------A------------'));
注意
+
而不是
*
。这将提供以下输出:

Array
(
    [0] => A
    [1] => *A*
    [2] => *A*
    [3] => *A*
    [4] => *A*
)
注意,第一个元素将保持不变,因为在A前后没有非alpha字符

#^[^\pL]+|[^\pL]+$#u
*
替换为
+
。将
*
$
结合使用并不像人们所期望的那样有效。正则表达式引擎如何工作的一个奇怪结果是,
X*$
将为
X*
找到两个匹配项。使用
+
修复它

解释 让我们看看正则表达式的这一部分,这一部分没有按预期工作。为什么在某些字符串的末尾放两个
*

  • 考虑替换第一组破折号后的第三个示例字符串
    --A---

    *A---$
    
  • 正则表达式引擎在此处查找正则表达式的匹配项:

    *A---$
      ^
    
  • 并用星号替换
    “--”

    *A*$
      ^
    
  • 然后将其内部光标移动到替换字符串的右侧

    *A*$
       ^
    
  • 它从这个光标位置开始,并寻找另一个匹配项。它找到了一个!它会找到
    -空字符串<代码>“由0个或多个非字母(
    [^\pL]*
    )组成,并且它被锚定在字符串的末尾(
    $
    ),因此它是一个有效的匹配项。它找到了空字符串,当然,但这是允许的

    这是意外的,因为它再次与
    $
    锚匹配。这不对吗?它不应该再匹配
    $
    ,是吗?事实上,它应该,而且确实如此。它可以再次匹配
    $
    ,因为
    $
    不是输入字符串中的实际字符,而是零宽度断言。它不会在第一次更换时“用完”<代码>$允许匹配两次

  • 因此,它用星号“替换”空字符串
    ”。这就是为什么你会有两个星号

    *A**$
       ^
    
  • 如果正则表达式引擎返回到步骤4,它将找到另一个空字符串并添加另一个星号。从概念上讲,这里有无限多的空字符串。为了避免这种情况,发动机不允许下一场比赛在与前一场比赛相同的位置开始。这条规则防止它进入无限循环


  • 试一试:
    在代码之后和代码主体内都给出了解释——作为注释

    <?php
    class String
    {
        private $str;
        public function __construct($str)
        {
            $this->str=$str;
        }
        public function replace($regex,$replacement)
        {
            return preg_replace($regex,$replacement,$this->str);
        }
    }
    
    function String($str)
    {
        return new String($str);
    }
    
    echo String('A')->replace('/^[^\pL]*|[^\pL]*$/','*').'<br />';//Outputs *A*
     //Why does this output *A* and not A?
     //Because it successfully matches an empty string
     //The easiest way to test for the presence of an empty string is like so:
    echo String('A')->replace('//','*').'<br />';//Outputs *A*
     //The engine begins by placing its internal pointer before the string like so:
     // A
     //^
     //It then tests the regular expression for the empty string ""
     //Most regular expressions will fail this test. But in our case matches it successfully.
     //Since we are preforming a search and replace the "" will get replaced by a "*" character
     //Then the internal pointer advances to the next character after its successful match
     // A
     // ^
     //It tests our regular expression for the A character and it fails.
     //Since we are performing a search and replace the searched "A" portion remains unchanged as "A"
     //The internal pointer advances to the next character
     // A
     //  ^
     //It tests our regular expression for the empty string ""
     //Again, most regular expressions will fail this test. But since ours successfully matched it,
     //The "" portion will get replaced by "*"
     //The engine then returns our output:
     //*A*
    echo '<hr />';
     //If we wanted to replace the A character too, we'd do this:
    echo String('A')->replace('/|A/','*').'<br />';//Outputs ***
     //Or we could do:
    echo String('A')->replace('/.*?/','*').'<br />';//Outputs ***
     //Thus we see for a 1 character string the engine will test for the empty spaces "" before and after the character as well
     //For a 19 character string it tests for all the gaps between each character like so:
    echo String('19 character string')->replace('//','*').'<br />';//Outputs *1*9* *c*h*a*r*a*c*t*e*r* *s*t*r*i*n*g*
     //For an empty string it would match once successfully like so:
    echo String('')->replace('//','*').'<br />';//Outputs *
    
    由于指针指向空字符串
    ,因此它会根据正则表达式对其进行测试。
    大多数正则表达式都会失败,因为满足正则表达式所需的最小字符数通常是一个或多个。但是在我们的例子中,匹配是成功的,因为0个字符是与正则表达式的有效匹配。
    由于我们正在执行搜索和替换,因此
    将替换为
    ”*“
    字符。
    成功匹配后,内部指针前进到下一个字符:

      A
    _ _ _
      ^
    
    它测试正则表达式中的
    “A”
    字符,结果失败
    由于我们正在执行搜索和替换,因此搜索到的
    “a”
    部分保持不变,即
    “a”

    内部指针前进到下一个字符

      A
    _ _ _
        ^
    
    它测试正则表达式中的空字符串
    “”

    同样,大多数正则表达式将无法通过此测试。
    但是,由于正则表达式成功地匹配了它,
    部分将被替换为
    “*”

    然后,引擎完成在字符串
    “A”中的循环,并返回我们的输出:
    “*A*”

    如果我们也想替换A字符,我们会这样做:
    echo字符串('A')->替换('/| A/','*')//输出***


    或者我们可以这样做:
    echo字符串('A')->替换('/.*?/','*')。
    //输出***


    因此,对于1个字符串,引擎将在字符前后测试


    对于19个字符的字符串,它会测试每个字符之间的所有间距,如:
    echo字符串('19个字符串')->替换('/','*')
    //输出*1*9**c*h*a*r*a*c*t*e*r**s*t*r*i*n*g*


    对于空字符串,它将成功匹配一次,如下所示:
    echo字符串(“”)->替换(“//”、“*”)//输出*

    我的解释到此为止。要修复正则表达式,请按照前面的建议操作并使用:
    /^[^\pL]+|[^\pL]+$/

    这将使满足正则表达式所需的最小字符数为1,从而解决不需要的行为

    最后一句话,如果有人想知道
    \pL
    在正则表达式中的作用,它的基本意思是:匹配任何类似字母的字符(与数字或符号相反)。这里解释如下:

    也许我误解了这个问题或正则表达式,但它似乎与两个选项中的一个匹配

    选项1:它匹配换行符或字符串的开头。然后它匹配一个字符
      A
    _ _ _
      ^
    
      A
    _ _ _
        ^
    
    /^[^\pL]*|[^\pL]*$/  
    ['A','-A-','---A---','-+*A*+-','------------A------------']