PHP Zastąpić ostatnie wystąpienie ciągu w łańcuchu?

Odpowiedzi:

228

Możesz użyć tej funkcji:

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

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

    return $subject;
}
Mischa
źródło
To wciąż powracało prawdą bez względu na wszystko. Rozważ zmodyfikowanie go na: if ($ pos) {$ subject = substr_replace ($ subject, $ replace, $ pos, strlen ($ search)); return $ subject; } else {return false; }
Jazzy,
4
@Jason Nie wraca TRUEbez względu na wszystko. Zwraca ciąg bez względu na wszystko. Jeśli nie można dokonać wymiany, zwraca oryginał $subject, tak jak substr_replace i str_replacezrób.
Mischa,
@Mischa Czy to nie to samo w tym przypadku? Próbowałem zrobić coś takiego jak! Str_lreplace, ale jeśli nie zwraca fałszu, jest uważane za prawdziwe, prawda? Tak czy inaczej, pomogło mi to i doceniam to. Dzięki.
Jazzy
1
Jak to działa? strpos — Find the position of the first occurrence of a substring in a string- edycja: wow. Geniusze PHP naprawdę stworzyli funkcję o nazwie strposi strrpos? Dzięki ...
BarryBones41
1
@Barry to jest jeden przypadek, w którym PHP nie zasługują winę :-) Nazwy są wzorowane na dziesiątków lat strstr, strrstrstandardowej biblioteki C, które są takie same funkcje. (Ale czy musieli zmienić nazwę?)
alexis
30

Kolejny 1-liniowy, ale bez 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
źródło
3
FWIW, przyjęte rozwiązanie jest około 35% szybsze niż to rozwiązanie.
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
źródło
Moim zdaniem najfajniejsze rozwiązanie, a jednocześnie łatwe do zrozumienia.
Blackbam
Dlaczego to działa z odwróconymi wszystkimi ciągami? Czy jest jakiś (zakładam) określony wzrost wydajności podczas używania wyrażeń regularnych?
Kamafeather
Nie, to faktycznie zmniejsza wydajność, ale to dlatego, że chcesz tylko ostatniego wystąpienia, więc ograniczasz wyszukiwanie do jednego i
odwracasz
15

Poniższe, raczej zwarte rozwiązanie, używa pozytywnego asercji wyprzedzającej PCRE, aby dopasować ostatnie wystąpienie podciągu będącego przedmiotem zainteresowania, to znaczy wystąpienie podciągu, po którym nie następuje żadne inne wystąpienie tego samego podciągu. W ten sposób przykład zastępuje last 'fox'z 'dog'.

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

WYNIK: 

The quick brown fox, fox, fox jumps over the lazy dog!!!
John Sonderson
źródło
5
Pomysł jest dobry, ale kod nie. To musi być:$string = 'The quick brown fox, fox, fox jumps over the lazy fox!!!'; echo preg_replace('/(fox(?!.*fox))/', 'dog', $string);
Roemer
Rzeczywiście, kod, który opublikowałem, zmienia wszystkie wystąpienia „fox” z wyjątkiem ostatniego na „pies”, ale to, czego chcemy, jest dokładnie odwrotne. Dziękuję za wskazanie, że zastąpienie? = Z?! rozwiązuje problem.
John Sonderson
11

Możesz to zrobić:

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

Wynik to „Hello John”;

pozdrowienia

Nicolas Finelli
źródło
4
Działa to, o ile nie ma żadnych powtarzających się znaków. W mojej sytuacji usuwam numer strony z daty archiwizacji, więc mam „2015-12 / 2” i wszystkie / i wszystkie 2 z końca stają się „2015-1”.
Mike
Działa to tylko wtedy, gdy ostatnie wyszukiwane wystąpienie jest ostatnim słowem i nie ma po nim żadnych dodatkowych znaków.
AwesomeGuy,
To nie działa, ponieważ rtrimnie zachowuje się tak, jak myślisz. Usuwa z końca wszystkie znaki, które istnieją w ciągu wyszukiwania w dowolnej kolejności (i zawsze dołącza zastąpienie), np. „Witaj słowo” -> „Witaj John”, „Witaj panie” -> „Witaj John”, „Witaj motor "->" Hello motJohn "," Hello worldy "->" Hello worldyJohn ".
Jake,
5

To również zadziała:

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

AKTUALIZACJA Nieco bardziej zwięzła wersja ( http://ideone.com/B8i4o ):

function str_lreplace($search, $replace, $subject)
{
    return preg_replace('~(.*)' . preg_quote($search, '~') . '~', '$1' . $replace, $subject, 1);
}
Alix Axel
źródło
Czy robię to źle? Jeśli tak, po prostu mnie zignoruj ​​:) ||| echo str_lreplace ("x", "y", "to x lub tamto x"); => Wynik
edorian
@edorian: Ups! Przepraszam, napisałem, że w pośpiechu, poprawna wersja jest tutaj: ideone.com/vR073 .
Alix Axel
5

Tylko jedna linia kodu (późna odpowiedź, ale warto ją dodać):

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

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

końcówka $ wskazuje koniec łańcucha.

Szczery
źródło
5

To odwieczne pytanie, ale dlaczego wszyscy pomijają najprostsze rozwiązanie oparte na wyrażeniach regularnych? Zwykłe kwantyfikatory regexp są chciwe, ludzie! Jeśli chcesz znaleźć ostatnią instancję wzoru, po prostu trzymaj się .*przed nim. Oto jak:

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

Spowoduje to zamianę ostatniego wystąpienia „fox” na „DUCK”, tak jak powinno, i wypisze:

The quick brown fox, fox, fox, DUCK, jumps over etc.
Alexis
źródło
1
Dzięki! Idealna funkcja do owinięcia mojej ekspresji, aby to osiągnąć. W moim przypadku ostatni przecinek zastępuję znakami „i”. Cieszę się, że przewinąłem trochę tę listę odpowiedzi.
rlhane
3
$string = "picture_0007_value";
$findChar =strrpos($string,"_");
if($findChar !== FALSE) {
  $string[$findChar]=".";
}

echo $string;

Oprócz błędów w kodzie, Faruk Unal ma najlepszą odpowiedź. Jedna funkcja załatwia sprawę.

xwero
źródło
Musisz sprawdzić, czy $ findChar nie jest fałszywe (tak samo jak w akceptowanej odpowiedzi). Jeśli ciąg nie zawiera szukanego ciągu, otrzymasz powiadomienie i pierwszy znak zostanie zastąpiony.
kudłaty
To świetnie, ale w obecnej formie może zastąpić tylko 1 znak 1 znakiem.
Pete,
3

Możesz użyć strrpos (), aby znaleźć ostatnie dopasowanie.

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

$string[$findChar]=".";

echo $string;

Wyjście: picture_0007.value

Faruk ÜNAL
źródło
2

Skrót do zaakceptowanej odpowiedzi

function str_lreplace($search, $replace, $subject){ 
    return is_numeric($pos=strrpos($subject,$search))?
    substr_replace($subject,$replace,$pos,strlen($search)):$subject;
}
Abbas
źródło
2

Krótka wersja:

$NewString = substr_replace($String,$Replacement,strrpos($String,$Replace),strlen($Replace));
Jeffrey the Giraffe
źródło
0

Użyj „$” w wyrażeniu reg, aby dopasować koniec ciągu

$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
źródło
4
działa to tylko wtedy, gdy ostatnie wystąpienie znajduje się na końcu łańcucha ideone.com/nbNSNq
cawecoy
1
To nie zadziała, jeśli po ostatnim „lisie” pojawią się inne postacie.
John Sonderson
0

Dla zainteresowanych: napisałem funkcję, która wykorzystuje preg_match, dzięki czemu można zastępować z prawej strony za pomocą wyrażenia regularnego.

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;
}

Lub jako skrótowe połączenie / implementacja obu opcji:

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;
}

na podstawie https://stackoverflow.com/a/3835653/3017716 i https://stackoverflow.com/a/23343396/3017716

Rozpoznać
źródło