PHP Substituir a última ocorrência de uma String em uma String?


Respostas:


228

Você pode usar esta função:

function str_lreplace($search, $replace, $subject)
{
    $pos = strrpos($subject, $search);

    if($pos !== false)
    {
        $subject = substr_replace($subject, $replace, $pos, strlen($search));
    }

    return $subject;
}

Isso ainda estava retornando verdade, não importa o quê. Considere modificá-lo para: if ($ pos) {$ subject = substr_replace ($ subject, $ replace, $ pos, strlen ($ search)); retornar $ subject; } else {return false; }
Jazzy

4
@ Jason Ele não retorna, TRUEnão importa o quê. Retorna uma string, não importa o quê. Se a substituição não pode ser feita devolve o original $subject, assim como substr_replace e str_replacefazer.
Mischa

@ Mischa Isso não é a mesma coisa neste caso? Eu estava tentando fazer algo como! Str_lreplace, mas se não retornar falso, é considerado verdadeiro, certo? De qualquer forma, isso me ajudou e eu aprecio isso. Obrigado.
Jazzy

1
Como isso pode funcionar? strpos — Find the position of the first occurrence of a substring in a string- editar: uau. Gênios php realmente fizeram uma função chamada strpose strrpos? Obrigado ....
BarryBones41

1
@ Barry, este é um caso em que o PHP não merece a culpa :-) Os nomes são padronizados com décadas de idade strstr, strrstrna biblioteca C padrão, que são as mesmas funções. (Mas será que eles têm para mudar o nome?)
alexis

30

Outro liner, mas sem preg:

$subject = 'bourbon, scotch, beer';
$search = ',';
$replace = ', and';

echo strrev(implode(strrev($replace), explode(strrev($search), strrev($subject), 2))); //output: bourbon, scotch, and beer

3
FWIW, a solução aceita é aproximadamente 35% mais rápida que esta solução.
JustCarty

27
$string = 'this is my world, not my world';
$find = 'world';
$replace = 'farm';
$result = preg_replace(strrev("/$find/"),strrev($replace),strrev($string),1);
echo strrev($result); //output: this is my world, not my farm

Solução mais legal na minha opinião e ainda fácil de entender.
Blackbam

Por que funciona com todas as strings invertidas? Existe algum (presumo) ganho de desempenho específico ao usar expressões regulares?
Kamafeather

Sem ele realmente diminui o desempenho, mas é porque você quer a última ocorrência única para que você limitar a pesquisa a um e tudo o inverso, se você queria a primeira você não teria para reverter qualquer coisa
Tofandel

15

A solução compacta a seguir usa a asserção lookahead positiva do PCRE para corresponder à última ocorrência da substring de interesse, ou seja, uma ocorrência da substring que não é seguida por nenhuma outra ocorrência da mesma substring. Assim, o exemplo substitui o last 'fox'por 'dog'.

$string = 'The quick brown fox, fox, fox jumps over the lazy fox!!!';
echo preg_replace('/(fox(?!.*fox))/', 'dog', $string);

RESULTADO: 

The quick brown fox, fox, fox jumps over the lazy dog!!!

5
A ideia é boa, mas o código não é. Ele deve ser:$string = 'The quick brown fox, fox, fox jumps over the lazy fox!!!'; echo preg_replace('/(fox(?!.*fox))/', 'dog', $string);
Roemer

De fato, o código que publiquei altera todas as instâncias de "raposa", com exceção da última, para "cachorro", mas o que queremos é exatamente o oposto. Obrigado por apontar que substituindo? = Por?! resolve o problema.
precisa saber é o seguinte

11

Você pode fazer isso:

$str = 'Hello world';
$str = rtrim($str, 'world') . 'John';

O resultado é 'Olá João';

Saudações


4
Isso funciona desde que não haja caracteres repetidos. Na minha situação, estou retirando o número da página da data do arquivo, para que eu tenha "2015-12 / 2" e leva tudo / e todos os 2 do final para "2015-1".
Mike

Isso funcionará apenas se a última ocorrência pesquisada for a última palavra e não tiver caracteres adicionais depois dela.
AwesomeGuy

Isso não funciona porque rtrimnão se comporta da maneira que você está pensando. Ele removerá do final todos os caracteres existentes na cadeia de pesquisa em qualquer ordem (e sempre acrescentará a substituição), por exemplo, "Hello word" -> "Hello John", "Hello John", "Hello lord" -> "Hello John", "Hello motor "->" Olá motJohn "," Olá mundano "->" Olá mundanoJohn ".
Jake

5

Isso também funcionará:

function str_lreplace($search, $replace, $subject)
{
    return preg_replace('~(.*)' . preg_quote($search, '~') . '(.*?)~', '$1' . $replace . '$2', $subject, 1);
}

ATUALIZAÇÃO Versão um pouco mais concisa ( http://ideone.com/B8i4o ):

function str_lreplace($search, $replace, $subject)
{
    return preg_replace('~(.*)' . preg_quote($search, '~') . '~', '$1' . $replace, $subject, 1);
}

Estou fazendo errado? Se sim, apenas me ignore :) ||| echo str_lreplace ("x", "y", "este x ou aquele x"); => Saída: "y" Veja: ideone.com/UXuTo
edorian

@edorian: Opa! Desculpe, eu postei isso com pressa, a versão correta está aqui: ideone.com/vR073 .
Alix Axel

5

Apenas uma linha de código (resposta tardia, mas vale a pena adicioná-la):

$string = 'The quick brown fox jumps over the lazy dog';
$find_me = 'dog';

preg_replace('/'. $find_me .'$/', '', $string);

o final $ indica o final da sequência.


5

Essa é uma pergunta antiga, mas por que todos estão ignorando a solução mais simples baseada em regexp? Os quantificadores normais de regexp são gananciosos, pessoal! Se você deseja encontrar a última instância de um padrão, fique .*na frente dele. Aqui está como:

$text = "The quick brown fox, fox, fox, fox, jumps over etc.";
$fixed = preg_replace("((.*)fox)", "$1DUCK", $text);
print($fixed);

Isso substituirá a última instância de "fox" para "DUCK", como deveria, e imprimirá:

The quick brown fox, fox, fox, DUCK, jumps over etc.

1
Obrigado! A função perfeita para envolver minha expressão para fazer isso. No meu caso, estou substituindo a última vírgula por "e". Ainda bem que rolei um pouco nesta lista de respostas.
rlhane

3
$string = "picture_0007_value";
$findChar =strrpos($string,"_");
if($findChar !== FALSE) {
  $string[$findChar]=".";
}

echo $string;

Além dos erros no código, Faruk Unal tem a melhor resposta. Uma função faz o truque.


Você precisa verificar se $ findChar não é falso (da mesma forma que na resposta aceita). Se a sequência não contiver a sequência pesquisada, você será notificado e o primeiro caractere será substituído.
shaggy

Isso é ótimo, mas, como está, ele pode substituir apenas 1 caractere por 1 caractere.
Pete

3

Você pode usar strrpos () para encontrar a última correspondência.

$string = "picture_0007_value";
$findChar =strrpos($string,"_");

$string[$findChar]=".";

echo $string;

Saída: picture_0007.value


2

Atalho para resposta aceita

function str_lreplace($search, $replace, $subject){ 
    return is_numeric($pos=strrpos($subject,$search))?
    substr_replace($subject,$replace,$pos,strlen($search)):$subject;
}

2

Uma versão curta:

$NewString = substr_replace($String,$Replacement,strrpos($String,$Replace),strlen($Replace));

0

Use o "$" em uma expressão reg para corresponder ao final da string

$string = 'The quick brown fox jumps over the lazy fox';
echo preg_replace('/fox$/', 'dog', $string);

//output
'The quick brown fox jumps over the lazy dog'

4
isso funciona apenas se a última ocorrência estiver no final da cadeia de caracteres ideone.com/nbNSNq
cawecoy

1
Isso não funcionará se outros caracteres aparecerem após a última 'raposa'.
John Sonderson

0

Para os interessados: eu escrevi uma função que utiliza preg_match para que você possa substituir do lado direito usando regex.

function preg_rreplace($search, $replace, $subject) {
    preg_match_all($search, $subject, $matches, PREG_SET_ORDER);
    $lastMatch = end($matches);

    if ($lastMatch && false !== $pos = strrpos($subject, $lastMatchedStr = $lastMatch[0])) {
        $subject = substr_replace($subject, $replace, $pos, strlen($lastMatchedStr));
    }

    return $subject;
}

Ou como uma combinação / implementação abreviada de ambas as opções:

function str_rreplace($search, $replace, $subject) {
    return (false !== $pos = strrpos($subject, $search)) ?
        substr_replace($subject, $replace, $pos, strlen($search)) : $subject;
}
function preg_rreplace($search, $replace, $subject) {
    preg_match_all($search, $subject, $matches, PREG_SET_ORDER);
    return ($lastMatch = end($matches)) ? str_rreplace($lastMatch[0], $replace, $subject) : $subject;
}

com base em https://stackoverflow.com/a/3835653/3017716 e https://stackoverflow.com/a/23343396/3017716

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.