如何使preg_replace只替换匹配的* * *字符中的第一个?

时间:2012-10-30 04:05:15

标签: php regex string preg-replace

例如,以下代码使用<i>标记包装每个匹配的字符。

echo preg_replace('/[aeiou]/', '<i>$0</i>', 'alphabet');
// result: <i>a</i>lph<i>a</i>b<i>e</i>t

但我希望它只能替换每个角色一次。

我正在寻找像<i>a</i>lphab<i>e</i>t这样的结果,其中第二个a没有标记,因为搜索字符串只有一个a

你能帮忙吗?如果没有遍历foreach循环中的每个字符,这是否可行?

答案还应该允许两个或多个相同的字符,每个字符只能使用一次。例如,如果我在字符串aaeioo中搜索alphabetsoupisgood,则它应该与a两个匹配,但只能匹配三个o中的两个&{} #39; S

6 个答案:

答案 0 :(得分:3)

如果你只想要一个字母只被替换一次,那么以下正则表达式应该有效:

echo preg_replace('/([aeiou])(?!.+?\\1)/', '<i>$1</i>', 'alphabet');

<强>输出:

alph<i>a</i>b<i>e</i>t

PS:请注意,它会替换最后一个字母而不是第一个字母。

修改

以下会产生与OP预期相同的输出(感谢@AntonyHatchkins):

echo strrev(preg_replace
        ('/([aeiou])(?!.+?\\1)/', strrev('<i>1$</i>'), strrev('alphabet')))."\n";

编辑2:

根据OP的评论:

Can you help me allow more than one a then? How can I match 2, but not 3 a's

我发布了这个答案:

echo strrev(preg_replace('/([aeiou])(?!(.+?\\1){2})/', 
            strrev('<i>1$</i>'), strrev('alphabetax'))) . "\n";

编辑3:

OP的另一个评论:

that will allow duplicates for all characters in the string, not just 2 a's & 1 e

我发布了这个答案:

echo strrev(preg_replace(array('/(a)(?!(.+?\\1){2})/', 
  '/(?<!>)([eiou])(?!.+?\\1)/'), 
  array(strrev('<i>1$</i>'), strrev('<i>1$</i>')), strrev('alphabetaxen')))."\n";

<强>输出:

<i>a</i>lph<i>a</i>b<i>e</i>taxen

注意:我认为原始问题已经改变了很多次,所以请不要在这个问题上增加更多的复杂性。如果您有不同的疑问,可以发布另一个问题。

答案 1 :(得分:0)

根据http://php.net/manual/es/function.preg-replace.php,您可以指定一个额外的参数来限制替换次数。

编辑:对不起,我最初没有得到您的问题。在那种情况下,它是不可能的。由于正则表达式的性质,它不知道它所取代的数量。我可能错了,但我怀疑是否存在正则表达式,每个字符只能替换一次。

你最好的选择是拨打5个电话,每个角色一个。像这样:

$res = preg_replace('/a/', '<i>$0</i>', 'alphabet', 1);
$res = preg_replace('/e/', '<i>$0</i>', 'alphabet', 1);
$res = preg_replace('/i/', '<i>$0</i>', 'alphabet', 1);
$res = preg_replace('/o/', '<i>$0</i>', 'alphabet', 1);
$res = preg_replace('/u/', '<i>$0</i>', 'alphabet', 1);

echo $res;

干杯

答案 2 :(得分:0)

使用

echo preg_replace('/[aeiou]/', ' ', 'alphabet', 1); 

对不起,我在你编辑你的问题之前已经开始了

这个怎么样。

$word = "alphabet";

$replace = array('a','e','i','o','u');
$with = array('','','','','');

echo str_replace($replace,$with,$word); //lphbt

答案 3 :(得分:0)

丑陋,但这是一种方法。

echo 
preg_replace('/a/','<i>$0</i>',
preg_replace('/e/','<i>$0</i>',
preg_replace('/i/','<i>$0</i>',
preg_replace('/o/','<i>$0</i>',
preg_replace('/u/','<i>$0</i>','alphabet',
1),1),1),1),1);

答案 4 :(得分:0)

这是使用preg_replace_callback()功能的另一种方法,所以我将其作为一个全新的答案发布。

function replace_first($matches) {
    static $used = array();
    $key = $matches[0];
    if (in_array($key,$used)) return $key;
    $used[] = $key;
    return '<i>' . $key . '</i>';
}

$str = preg_replace_callback('/[aeiou]/','replace_first','alphabet');
echo $str;

将输出<i>a</i>lphab<i>e</i>t

答案 5 :(得分:-1)

我能做的最好就是遍历每个角色。 (我尽可能避免循环)我希望有一种更清洁的方式,但现在这样做。

$word = 'alphabetsoupisgood';
$match = 'aaeou';
$wordArr = str_split($word);
$matchArr = str_split($capitals);

foreach ($matchArr as $c) {
    $key = array_search($c, $wordArr);
    if ($key !== false) {
        $wordArr[$key] = strtoupper($c);
    }
}

foreach ($wordArr as $k => $c) {
    if (ctype_upper($c)) {
        $wordArr[$k] = '<i>' . strtolower($c) . '</i>';
    }
}
$word = implode('',$wordArr);
echo $word;

这是在键盘中但他们正在运行一些超级旧版本的PHP,因此ctype_upper未启用... http://codepad.org/UoLWcK2S

如果有人可以使用preg_replace提供更清晰的答案,我很乐意将你的答案标记为答案。