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;
}
Mischa
fonte
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
ricka
fonte
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
zack
fonte
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!!!
John Sonderson
fonte
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

Nicolas Finelli
fonte
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);
}
Alix Axel
fonte
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.

Frank
fonte
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.
alexis
fonte
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.

xwero
fonte
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

Faruk ÜNAL
fonte
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;
}
Abbas
fonte
2

Uma versão curta:

$NewString = substr_replace($String,$Replacement,strrpos($String,$Replace),strlen($Replace));
Jeffrey, a girafa
fonte
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'
Neil Holcomb
fonte
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

Ken
fonte