试一试:
在代码之后和代码正文中都给出了解释——作为 cmets。
<?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 *
echo String('A')->replace('/^[^\pL]*|[^\pL]*$/','*');//Outputs *A*
为什么上面的输出是*A* 而不是A?
因为这个正则表达式将成功匹配空字符串""。
使用空的正则表达式观察到相同的行为,如下所示:
echo String('A')->replace('//','*');//Outputs *A*
我现在将解释 为什么正则表达式engine实现会产生这些奇怪的结果。之后你会明白他们一点都不奇怪,但实际上是正确的行为。
引擎首先将其 内部指针 放在字符串之前,如下所示:
A
_ _ _
^
由于指针指向空字符串"",然后它会根据我们的正则表达式对其进行测试。
大多数正则表达式将无法通过此测试,因为满足正则表达式所需的最少字符数通常是一个或多个。但在我们的例子中,匹配是成功的,因为 0 个字符是对我们正则表达式的有效匹配。
由于我们正在执行搜索和替换,"" 将被 "*" 字符替换。
然后内部指针在匹配成功后前进到下一个字符:
A
_ _ _
^
它测试"A" 字符的正则表达式,它失败。
由于我们正在执行搜索和替换,搜索到的"A" 部分保持不变为"A"
内部指针前进到下一个字符:
A
_ _ _
^
它测试我们的正则表达式是否为空字符串""
同样,大多数正则表达式都无法通过此测试。
但由于我们的正则表达式 成功 匹配它,"" 部分将被 "*" 替换
引擎然后完成遍历我们的字符串"A"并返回我们的输出:"*A*"
如果我们也想替换 A 字符,我们会这样做:
echo String('A')->replace('/|A/','*');//Outputs ***
或者我们可以这样做:
echo String('A')->replace('/.*?/','*').'<br />';//Outputs ***
因此,我们看到对于 1 个字符的字符串,引擎也会在字符之前和之后测试 ""。
对于 19 个字符的字符串,它会测试每个字符之间的所有间隙,如下所示:
echo String('19 character string')->replace('//','*');
//Outputs *1*9* *c*h*a*r*a*c*t*e*r* *s*t*r*i*n*g*
对于空字符串,它会成功匹配一次,如下所示:
echo String('')->replace('//','*');//Outputs *
我的解释到此结束。要修复您的正则表达式,请按照之前的建议进行操作并使用:
/^[^\pL]+|[^\pL]+$/
这将使满足正则表达式所需的最少字符数,从而解决不需要的行为。
最后,如果有人想知道\pL 在正则表达式中的作用,它的基本意思是:匹配任何类似字母的字符(而不是数字或符号)。这里解释:
http://www.php.net/manual/en/regexp.reference.unicode.php