Chcę, aby wersja str_replace()
tego zastąpiła tylko pierwsze wystąpienie $search
w $subject
. Czy istnieje na to łatwe rozwiązanie, czy też potrzebuję rozwiązania hacky?
Chcę, aby wersja str_replace()
tego zastąpiła tylko pierwsze wystąpienie $search
w $subject
. Czy istnieje na to łatwe rozwiązanie, czy też potrzebuję rozwiązania hacky?
Odpowiedzi:
Można to zrobić za pomocą preg_replace :
function str_replace_first($from, $to, $content)
{
$from = '/'.preg_quote($from, '/').'/';
return preg_replace($from, $to, $content, 1);
}
echo str_replace_first('abc', '123', 'abcdef abcdef abcdef');
// outputs '123def abcdef abcdef'
Magia tkwi w opcjonalnym czwartym parametrze [Limit]. Z dokumentacji:
[Limit] - Maksymalna możliwa zamiana dla każdego wzoru w każdym ciągu tematycznym. Domyślnie -1 (bez limitu).
Jednak zobacz odpowiedź zombata na bardziej wydajną metodę (z grubsza, 3-4x szybciej).
preg_quote
? Na przykład @ThomasRedstone martwi się, że separator /
może być niebezpieczny, jeśli się pojawi $from
, ale na szczęście tak nie jest: jest poprawnie uciekany z powodu preg_quote
drugiego parametru (można to łatwo przetestować). Chciałbym usłyszeć o konkretnych problemach (które mogłyby stanowić poważne błędy bezpieczeństwa PCRE w mojej książce).
Nie ma żadnej wersji, ale rozwiązanie wcale nie jest hakujące.
$pos = strpos($haystack, $needle);
if ($pos !== false) {
$newstring = substr_replace($haystack, $replace, $pos, strlen($needle));
}
Całkiem proste i oszczędza karę wydajności wyrażeń regularnych.
Premia: Jeśli chcesz zastąpić ostatnie wystąpienie, po prostu użyj strrpos
zamiast strpos
.
substr_replace
jest to dość niewygodna funkcja ze względu na wszystkie parametry, prawdziwym problemem jest to, że manipulowanie ciągami liczbowymi jest czasami trudne - musisz uważać, aby przekazać odpowiednią zmienną / offset do funkcji. I tak posunąłbym się do stwierdzenia, że powyższy kod jest najprostszym, i dla mnie, logicznym, podejściem.
Edycja: obie odpowiedzi zostały zaktualizowane i są teraz poprawne. Pozostawię odpowiedź, ponieważ czasy funkcji są nadal przydatne.
Odpowiedzi „zombat” i „za dużo php” są niestety nieprawidłowe. To jest korekta opublikowanej odpowiedzi zombat (ponieważ nie mam wystarczającej reputacji, aby opublikować komentarz):
$pos = strpos($haystack,$needle);
if ($pos !== false) {
$newstring = substr_replace($haystack,$replace,$pos,strlen($needle));
}
Zanotuj strlen ($ igła), zamiast strlen ($ replace). Przykład Zombata będzie działał poprawnie tylko wtedy, gdy igła i zamiennik będą tej samej długości.
Oto ta sama funkcjonalność w funkcji z tym samym podpisem, co własny str_replace PHP:
function str_replace_first($search, $replace, $subject) {
$pos = strpos($subject, $search);
if ($pos !== false) {
return substr_replace($subject, $replace, $pos, strlen($search));
}
return $subject;
}
Oto poprawiona odpowiedź „za dużo php”:
implode($replace, explode($search, $subject, 2));
Zwróć uwagę na 2 na końcu zamiast 1. Lub w formacie funkcji:
function str_replace_first($search, $replace, $subject) {
return implode($replace, explode($search, $subject, 2));
}
Zmierzyłem czas obu funkcji, a pierwsza jest dwa razy szybsza, gdy nie znaleziono dopasowania. Są takie same prędkości po znalezieniu dopasowania.
stripos()
na ratunek :-)
Zastanawiałem się, który z nich był najszybszy, więc przetestowałem je wszystkie.
Poniżej znajdziesz:
Wszystkie funkcje zostały przetestowane przy tych samych ustawieniach:
$string = 'OOO.OOO.OOO.S';
$search = 'OOO';
$replace = 'B';
Funkcje, które zastępują tylko pierwsze wystąpienie ciągu w ciągu:
substr_replace($string, $replace, 0, strlen($search));
[CONTRIBUTED BY] => zombat
[OOO.OOO.OOO.S] => B.OOO.OOO.S
[AVERAGE TIME] => 0.0000062883
[SLOWER BY] => FASTEST
replace_first($search, $replace, $string);
[CONTRIBUTED BY] => too much php
[OOO.OOO.OOO.S] => B.OOO.OOO.S
[AVERAGE TIME] => 0.0000073902
[SLOWER BY] => 17.52%
preg_replace($search, $replace, $string, 1);
[CONTRIBUTED BY] => karim79
[OOO.OOO.OOO.S] => B.OOO.OOO.S
[AVERAGE TIME] => 0.0000077519
[SLOWER BY] => 23.27%
str_replace_once($search, $replace, $string);
[CONTRIBUTED BY] => happyhardik
[OOO.OOO.OOO.S] => B.OOO.OOO.S
[AVERAGE TIME] => 0.0000082286
[SLOWER BY] => 30.86%
str_replace_limit($search, $replace, $string, $count, 1);
[CONTRIBUTED BY] => bfrohs - expanded renocor
[OOO.OOO.OOO.S] => B.OOO.OOO.S
[AVERAGE TIME] => 0.0000083342
[SLOWER BY] => 32.54%
str_replace_limit($search, $replace, $string, 1);
[CONTRIBUTED BY] => renocor
[OOO.OOO.OOO.S] => B.OOO.OOO.S
[AVERAGE TIME] => 0.0000093116
[SLOWER BY] => 48.08%
str_replace_limit($string, $search, $replace, 1, 0);
[CONTRIBUTED BY] => jayoaK
[OOO.OOO.OOO.S] => B.OOO.OOO.S
[AVERAGE TIME] => 0.0000093862
[SLOWER BY] => 49.26%
Funkcje, które zastępują tylko ostatnie wystąpienie ciągu w ciągu:
substr_replace($string, $replace, strrpos($string, $search), strlen($search));
[CONTRIBUTED BY] => oLinkSoftware - modified zombat
[OOO.OOO.OOO.S] => OOO.OOO.B.S
[AVERAGE TIME] => 0.0000068083
[SLOWER BY] => FASTEST
strrev(implode(strrev($replace), explode(strrev($search), strrev($string), 2)));
[CONTRIBUTED BY] => oLinkSoftware
[OOO.OOO.OOO.S] => OOO.OOO.B.S
[AVERAGE TIME] => 0.0000084460
[SLOWER BY] => 24.05%
substr_replace()
wygrywa wynik, jest prosty; ponieważ jest to funkcja wewnętrzna. Dwie funkcje wewnętrzne i funkcje zdefiniowane przez użytkownika różnią się pod względem wydajności, ponieważ wewnętrzna działa w niższych warstwach. Dlaczego więc nie preg_match()
? Wyrażenia regularne są prawie wolniejsze niż każda wewnętrzna funkcja manipulacji ciągiem, ze względu na ich naród wyszukiwania w ciągu wiele razy.
substr_replace($string, $replace, 0, strlen($search));
) nie tylko napisał to statyczne 0
. Częścią splotu rozwiązań innych niż wyrażenia regularne jest to, że muszą „znaleźć” punkt wyjścia, zanim będą wiedzieć, gdzie wymienić.
Niestety nie znam żadnej funkcji PHP, która mogłaby to zrobić.
Możesz rzucić własnym dość łatwo w ten sposób:
function replace_first($find, $replace, $subject) {
// stolen from the comments at PHP.net/str_replace
// Splits $subject into an array of 2 items by $find,
// and then joins the array with $replace
return implode($replace, explode($find, $subject, 2));
}
return implode($replace, explode($find, $subject, $limit+1));
dla niestandardowych numerów wymiany
Stworzyłem tę małą funkcję, która zamienia ciąg znaków na ciąg znaków (wielkość liter ma znaczenie) z limitem, bez potrzeby Regexp. To działa dobrze.
function str_replace_limit($search, $replace, $string, $limit = 1) {
$pos = strpos($string, $search);
if ($pos === false) {
return $string;
}
$searchLen = strlen($search);
for ($i = 0; $i < $limit; $i++) {
$string = substr_replace($string, $replace, $pos, $searchLen);
$pos = strpos($string, $search);
if ($pos === false) {
break;
}
}
return $string;
}
Przykładowe użycie:
$search = 'foo';
$replace = 'bar';
$string = 'foo wizard makes foo brew for evil foo and jack';
$limit = 2;
$replaced = str_replace_limit($search, $replace, $string, $limit);
echo $replaced;
// bar wizard makes bar brew for evil foo and jack
===false
zamiast is_bool(
być bardziej wyraźnym - kciuk w górę, tylko dlatego, że udało mi się uniknąć szaleństwa RegExp ! ... a jednocześnie działa i czyste rozwiązanie ...
preg_
rozwiązania nie jest szaleństwem, ale osobistą preferencją. return preg_replace('/'.preg_quote($search, '/').'/', $replace, $content, 1);
jest dość łatwy do odczytania dla osób, które nie boją się wyrażeń regularnych. Potrzebujesz wyszukiwania bez rozróżniania wielkości liter? Dodaj i
po ograniczniku wzoru końcowego. Potrzebujesz obsługi Unicode / Multibyte? Dodaj u
po ograniczniku wzoru końcowego. Potrzebujesz obsługi granicy słów? Dodaj \b
po obu stronach szukanego ciągu. Jeśli nie chcesz wyrażenia regularnego, nie używaj wyrażenia regularnego. Konie na kursy, ale na pewno nie szaleństwo.
Najprostszym sposobem byłoby użycie wyrażenia regularnego.
Innym sposobem jest znalezienie pozycji ciągu za pomocą strpos (), a następnie substr_replace ()
Ale naprawdę wybrałbym RegExp.
function str_replace_once($search, $replace, $subject) {
$pos = strpos($subject, $search);
if ($pos === false) {
return $subject;
}
return substr($subject, 0, $pos) . $replace . substr($subject, $pos + strlen($search));
}
=> KOD ZOSTAŁ ZMIENIONY, więc uważaj niektóre komentarze za stare
I dziękuję wszystkim za pomoc w ulepszeniu tego
Wszelkie BŁĘDY, proszę o poinformowanie mnie; Zaraz to naprawię
Więc chodźmy na:
Zamiana pierwszego „o” na „ea” na przykład:
$s='I love you';
$s=str_replace_first('o','ea',$s);
echo $s;
//output: I leave you
Funkcja:
function str_replace_first($a,$b,$s)
{
$w=strpos($s,$a);
if($w===false)return $s;
return substr($s,0,$w).$b.substr($s,$w+strlen($a));
}
substr($where,$b+strlen($this))
, nie substr($where,$b+1)
. I myślę, że substr_replace
to jest szybsze.
$string = 'this is my world, not my world';
$find = 'world';
$replace = 'farm';
$result = preg_replace("/$find/",$replace,$string,1);
echo $result;
preg_quote
z $find
przed użyciem go jako wyrazu.
preg_quote()
. Tę późno zduplikowaną odpowiedź można bezpiecznie usunąć ze strony, ponieważ jej porady są udzielane przez wcześniejszą i wyżej ocenianą akceptowaną odpowiedź.
Aby rozwinąć odpowiedź @ renocor , napisałem funkcję, która jest w 100% kompatybilna wstecz str_replace()
. Oznacza to, że można zastąpić wszystkie wystąpienia str_replace()
ze str_replace_limit()
nie brudząc się niczego, nawet tych z wykorzystaniem tablic dla $search
, $replace
i / lub$subject
.
Funkcja może być całkowicie samodzielna, jeśli chcesz zastąpić wywołanie funkcji ($string===strval(intval(strval($string))))
, ale odradzam to, ponieważ valid_integer()
jest to dość przydatna funkcja w przypadku liczb całkowitych podanych jako łańcuchy.
Uwaga: Gdy tylko jest to możliwe, str_replace_limit()
użyje str_replace()
zamiast tego, więc wszystkie połączenia z str_replace()
można zastąpićstr_replace_limit()
bez obawy o obniżenie wydajności.
<?php
$search = 'a';
$replace = 'b';
$subject = 'abcabc';
$limit = -1; // No limit
$new_string = str_replace_limit($search, $replace, $subject, $count, $limit);
echo $count.' replacements -- '.$new_string;
2 zamienniki - bbcbbc
$limit = 1; // Limit of 1
$new_string = str_replace_limit($search, $replace, $subject, $count, $limit);
echo $count.' replacements -- '.$new_string;
1 zamienniki - bbcabc
$limit = 10; // Limit of 10
$new_string = str_replace_limit($search, $replace, $subject, $count, $limit);
echo $count.' replacements -- '.$new_string;
2 zamienniki - bbcbbc
<?php
/**
* Checks if $string is a valid integer. Integers provided as strings (e.g. '2' vs 2)
* are also supported.
* @param mixed $string
* @return bool Returns boolean TRUE if string is a valid integer, or FALSE if it is not
*/
function valid_integer($string){
// 1. Cast as string (in case integer is provided)
// 1. Convert the string to an integer and back to a string
// 2. Check if identical (note: 'identical', NOT just 'equal')
// Note: TRUE, FALSE, and NULL $string values all return FALSE
$string = strval($string);
return ($string===strval(intval($string)));
}
/**
* Replace $limit occurences of the search string with the replacement string
* @param mixed $search The value being searched for, otherwise known as the needle. An
* array may be used to designate multiple needles.
* @param mixed $replace The replacement value that replaces found search values. An
* array may be used to designate multiple replacements.
* @param mixed $subject The string or array being searched and replaced on, otherwise
* known as the haystack. If subject is an array, then the search and replace is
* performed with every entry of subject, and the return value is an array as well.
* @param string $count If passed, this will be set to the number of replacements
* performed.
* @param int $limit The maximum possible replacements for each pattern in each subject
* string. Defaults to -1 (no limit).
* @return string This function returns a string with the replaced values.
*/
function str_replace_limit(
$search,
$replace,
$subject,
&$count,
$limit = -1
){
// Set some defaults
$count = 0;
// Invalid $limit provided. Throw a warning.
if(!valid_integer($limit)){
$backtrace = debug_backtrace();
trigger_error('Invalid $limit `'.$limit.'` provided to '.__function__.'() in '.
'`'.$backtrace[0]['file'].'` on line '.$backtrace[0]['line'].'. Expecting an '.
'integer', E_USER_WARNING);
return $subject;
}
// Invalid $limit provided. Throw a warning.
if($limit<-1){
$backtrace = debug_backtrace();
trigger_error('Invalid $limit `'.$limit.'` provided to '.__function__.'() in '.
'`'.$backtrace[0]['file'].'` on line '.$backtrace[0]['line'].'. Expecting -1 or '.
'a positive integer', E_USER_WARNING);
return $subject;
}
// No replacements necessary. Throw a notice as this was most likely not the intended
// use. And, if it was (e.g. part of a loop, setting $limit dynamically), it can be
// worked around by simply checking to see if $limit===0, and if it does, skip the
// function call (and set $count to 0, if applicable).
if($limit===0){
$backtrace = debug_backtrace();
trigger_error('Invalid $limit `'.$limit.'` provided to '.__function__.'() in '.
'`'.$backtrace[0]['file'].'` on line '.$backtrace[0]['line'].'. Expecting -1 or '.
'a positive integer', E_USER_NOTICE);
return $subject;
}
// Use str_replace() whenever possible (for performance reasons)
if($limit===-1){
return str_replace($search, $replace, $subject, $count);
}
if(is_array($subject)){
// Loop through $subject values and call this function for each one.
foreach($subject as $key => $this_subject){
// Skip values that are arrays (to match str_replace()).
if(!is_array($this_subject)){
// Call this function again for
$this_function = __FUNCTION__;
$subject[$key] = $this_function(
$search,
$replace,
$this_subject,
$this_count,
$limit
);
// Adjust $count
$count += $this_count;
// Adjust $limit, if not -1
if($limit!=-1){
$limit -= $this_count;
}
// Reached $limit, return $subject
if($limit===0){
return $subject;
}
}
}
return $subject;
} elseif(is_array($search)){
// Only treat $replace as an array if $search is also an array (to match str_replace())
// Clear keys of $search (to match str_replace()).
$search = array_values($search);
// Clear keys of $replace, if applicable (to match str_replace()).
if(is_array($replace)){
$replace = array_values($replace);
}
// Loop through $search array.
foreach($search as $key => $this_search){
// Don't support multi-dimensional arrays (to match str_replace()).
$this_search = strval($this_search);
// If $replace is an array, use the value of $replace[$key] as the replacement. If
// $replace[$key] doesn't exist, just an empty string (to match str_replace()).
if(is_array($replace)){
if(array_key_exists($key, $replace)){
$this_replace = strval($replace[$key]);
} else {
$this_replace = '';
}
} else {
$this_replace = strval($replace);
}
// Call this function again for
$this_function = __FUNCTION__;
$subject = $this_function(
$this_search,
$this_replace,
$subject,
$this_count,
$limit
);
// Adjust $count
$count += $this_count;
// Adjust $limit, if not -1
if($limit!=-1){
$limit -= $this_count;
}
// Reached $limit, return $subject
if($limit===0){
return $subject;
}
}
return $subject;
} else {
$search = strval($search);
$replace = strval($replace);
// Get position of first $search
$pos = strpos($subject, $search);
// Return $subject if $search cannot be found
if($pos===false){
return $subject;
}
// Get length of $search, to make proper replacement later on
$search_len = strlen($search);
// Loop until $search can no longer be found, or $limit is reached
for($i=0;(($i<$limit)||($limit===-1));$i++){
// Replace
$subject = substr_replace($subject, $replace, $pos, $search_len);
// Increase $count
$count++;
// Get location of next $search
$pos = strpos($subject, $search);
// Break out of loop if $needle
if($pos===false){
break;
}
}
// Return new $subject
return $subject;
}
}
E_USER_WARNING
przez cały czas, co jest ostrzeżenie , nie błąd . Śledzenie jest niezwykle przydatne, aby dowiedzieć się, jaki kod przekazuje nieprawidłowe dane do funkcji w pierwszej kolejności (co jest absolutnie niezbędne do śledzenia błędów w produkcji). Jeśli chodzi o powrót $subject
zamiast false
/ null
lub zgłoszenie błędu, był to po prostu osobisty wybór dla mojego przypadku użycia. Aby dopasować str_replace()
funkcjonalność, najlepszym rozwiązaniem byłoby użycie wykrywalnych błędów krytycznych (podobnie str_replace()
jak w przypadku zamknięcia dwóch pierwszych argumentów).
preg_replace()
. Ponadto preg_replace()
/ regex oferuje obsługę granicy słów (jeśli jest to pożądane) - coś, czego funkcje inne niż wyrażenia regularne nie zapewnią elegancko.
Zgodnie z moim wynikiem testu chciałbym głosować na regular_express dostarczony przez karim79. (Nie mam wystarczającej reputacji, aby głosować teraz!)
Rozwiązanie zombat wykorzystuje zbyt wiele wywołań funkcji, ja nawet upraszczam kody. Używam PHP 5.4 do uruchomienia obu rozwiązań 100 000 razy, a oto wynik:
$str = 'Hello abc, have a nice day abc! abc!';
$pos = strpos($str, 'abc');
$str = substr_replace($str, '123', $pos, 3);
==> 1,85 sek
$str = 'Hello abc, have a nice day abc! abc!';
$str = preg_replace('/abc/', '123', $str, 1);
==> 1,35 sek
Jak widzisz. Wydajność preg_replace nie jest tak zła, jak wielu myśli. Proponuję więc klasyczne rozwiązanie, jeśli twój regularny ekspres nie jest skomplikowany.
$pos
za false
, więc gdy igła nie istnieje w stogu siana, to uszkodzić wyjście.
Aby rozwinąć odpowiedź zombata (którą uważam za najlepszą), stworzyłem rekurencyjną wersję jego funkcji, która przyjmuje $limit
parametr określający, ile wystąpień chcesz zastąpić.
function str_replace_limit($haystack, $needle, $replace, $limit, $start_pos = 0) {
if ($limit <= 0) {
return $haystack;
} else {
$pos = strpos($haystack,$needle,$start_pos);
if ($pos !== false) {
$newstring = substr_replace($haystack, $replace, $pos, strlen($needle));
return str_replace_limit($newstring, $needle, $replace, $limit-1, $pos+strlen($replace));
} else {
return $haystack;
}
}
}
$start_pos
, więc jeśli to jest poza długością łańcucha, funkcja ta będzie generować: Warning: strpos(): Offset not contained in string...
. Ta funkcja nie zastępuje, gdy $start_pos
jest poza długością. Dowód niepowodzenia: 3v4l.org/qGuVIR ... Twoja funkcja może łączyć return $haystack
warunki i unikać deklarowania zmiennych jednorazowych, takich jak: 3v4l.org/Kdmqp Jednak, jak powiedziałem w komentarzach w innym miejscu na tej stronie, wolałbym użyj bardzo czystego, bezpośredniego, nierekurencyjnego preg_replace()
połączenia.
else
linijkę$start_pos > strlen($haystack) ? $start_pos = strlen($haystack) : '';
Dla sznurka
$string = 'OOO.OOO.OOO.S';
$search = 'OOO';
$replace = 'B';
//replace ONLY FIRST occurance of "OOO" with "B"
$string = substr_replace($string,$replace,0,strlen($search));
//$string => B.OOO.OOO.S
//replace ONLY LAST occurance of "OOOO" with "B"
$string = substr_replace($string,$replace,strrpos($string,$search),strlen($search))
//$string => OOO.OOO.B.S
//replace ONLY LAST occurance of "OOOO" with "B"
$string = strrev(implode(strrev($replace),explode(strrev($search),strrev($string),2)))
//$string => OOO.OOO.B.S
Dla jednego znaku
$string[strpos($string,$search)] = $replace;
//EXAMPLE
$string = 'O.O.O.O.S';
$search = 'O';
$replace = 'B';
//replace ONLY FIRST occurance of "O" with "B"
$string[strpos($string,$search)] = $replace;
//$string => B.O.O.O.S
//replace ONLY LAST occurance of "O" with "B"
$string[strrpos($string,$search)] = $replace;
// $string => B.O.O.B.S
substr_replace()
techniki uszkadzają łańcuch wejściowy, gdy szukana wartość nie jest obecna. Dowód niepowodzenia: 3v4l.org/HmEml (I ta ostatnia technika ze wszystkimi rev
wywołaniami jest poważnie zawiła / trudna dla oczu.)
Uzupełniając to, co mówili ludzie, pamiętaj, że cały ciąg jest tablicą:
$string = "Lorem ipsum lá lá lá";
$string[0] = "B";
echo $string;
„Borem ipsum lá lá lá”
á
. Demonstracja niepowodzenia
string
ciąg wielobajtowy, używającmb_strlen($subject) != strlen($subject)
$str = "/property/details&id=202&test=123#tab-6p";
$position = strpos($str,"&");
echo substr_replace($str,"?",$position,1);
Za pomocą substr_replace możemy zastąpić wystąpienie pierwszego znaku tylko ciągiem. ponieważ & jest powtarzane wiele razy, ale tylko na pierwszej pozycji musimy go zastąpić?
Ta funkcja jest silnie zainspirowana odpowiedzią @renocor. To sprawia, że funkcja jest wielobajtowa bezpieczna.
function str_replace_limit($search, $replace, $string, $limit)
{
$i = 0;
$searchLength = mb_strlen($search);
while(($pos = mb_strpos($string, $search)) !== false && $i < $limit)
{
$string = mb_substr_replace($string, $replace, $pos, $searchLength);
$i += 1;
}
return $string;
}
function mb_substr_replace($string, $replacement, $start, $length = null, $encoding = null)
{
$string = (array)$string;
$encoding = is_null($encoding) ? mb_internal_encoding() : $encoding;
$length = is_null($length) ? mb_strlen($string) - $start : $length;
$string = array_map(function($str) use ($replacement, $start, $length, $encoding){
$begin = mb_substr($str, 0, $start, $encoding);
$end = mb_substr($str, ($start + $length), mb_strlen($str), $encoding);
return $begin . $replacement . $end;
}, $string);
return ( count($string) === 1 ) ? $string[0] : $string;
}
Możesz użyć tego:
function str_replace_once($str_pattern, $str_replacement, $string){
if (strpos($string, $str_pattern) !== false){
$occurrence = strpos($string, $str_pattern);
return substr_replace($string, $str_replacement, strpos($string, $str_pattern), strlen($str_pattern));
}
return $string;
}
Znaleziono ten przykład z php.net
Stosowanie:
$string = "Thiz iz an examplz";
var_dump(str_replace_once('z','Z', $string));
Wynik:
ThiZ iz an examplz
Może to nieco obniżyć wydajność, ale jest to najłatwiejsze rozwiązanie.
strpos()
). Odebrane, ponieważ nie dodaje żadnej nowej wartości do strony.
Jeśli ciąg nie zawiera żadnych znaków wielobajtowych i jeśli chcesz zastąpić tylko jeden znak, możesz po prostu użyć strpos
Tutaj funkcja obsługująca błędy
/**
* Replace the first occurence of given string
*
* @param string $search a char to search in `$subject`
* @param string $replace a char to replace in `$subject`
* @param string $subject
* @return string
*
* @throws InvalidArgumentException if `$search` or `$replace` are invalid or if `$subject` is a multibytes string
*/
function str_replace_first(string $search , string $replace , string $subject) : string {
// check params
if(strlen($replace) != 1 || strlen($search) != 1) {
throw new InvalidArgumentException('$search & $replace must be char');
}elseif(mb_strlen($subject) != strlen($subject)){
throw new InvalidArgumentException('$subject is an multibytes string');
}
// search
$pos = strpos($subject, $search);
if($pos === false) {
// not found
return $subject;
}
// replace
$subject[$replace] = $subject;
return $subject;
}
Rozwiązanie Loop
<?php
echo replaceFirstMatchedChar("&", "?", "/property/details&id=202&test=123#tab-6");
function replaceFirstMatchedChar($searchChar, $replaceChar, $str)
{
for ($i = 0; $i < strlen($str); $i++) {
if ($str[$i] == $searchChar) {
$str[$i] = $replaceChar;
break;
}
}
return $str;
}
Oto prosta klasa, którą stworzyłem, aby zawinąć nieco zmodyfikowaną str_replace () funkcje .
Nasza funkcja php :: str_rreplace () pozwala również na wykonanie odwróconego, ograniczonego str_replace (), co może być bardzo przydatne, gdy próbujesz zastąpić tylko ostatnie X wystąpienie ciągu.
W obu tych przykładach użyto preg_replace () .
<?php
class php {
/**
* str_replace() from the end of a string that can also be limited e.g. replace only the last instance of '</div>' with ''
*
* @param string $find
* @param string $replace
* @param string $subject
* @param int $replacement_limit | -1 to replace all references
*
* @return string
*/
public static function str_replace($find, $replace, $subject, $replacement_limit = -1) {
$find_pattern = str_replace('/', '\/', $find);
return preg_replace('/' . $find_pattern . '/', $replace, $subject, $replacement_limit);
}
/**
* str_replace() from the end of a string that can also be limited e.g. replace only the last instance of '</div>' with ''
*
* @param string $find
* @param string $replace
* @param string $subject
* @param int $replacement_limit | -1 to replace all references
*
* @return string
*/
public static function str_rreplace($find, $replace, $subject, $replacement_limit = -1) {
return strrev( self::str_replace(strrev($find), strrev($replace), strrev($subject), $replacement_limit) );
}
}
$str = "Hello there folks!"
$str_ex = explode("there, $str, 2); //explodes $string just twice
//outputs: array ("Hello ", " folks")
$str_final = implode("", $str_ex); // glues above array together
// outputs: str("Hello folks")
Jest jeszcze jedna dodatkowa przestrzeń, ale nie miało to znaczenia, jak w moim przypadku dla skryptu backgound.
to jest moja pierwsza odpowiedź tutaj, mam nadzieję, że zrobię to poprawnie. Dlaczego nie użyć czwartego argumentu funkcji str_replace dla tego problemu?
mixed str_replace ( mixed $search , mixed $replace , mixed $subject [, int &$count ] )
count: Jeśli przejdzie, zostanie ustawiona liczba wykonanych zamian.
edytuj: Ta odpowiedź jest niepoprawna, ponieważ czwarty parametr str_replace jest zmienną, której przypisuje się liczbę wykonanych zamian. Jest to niespójne z preg_replace , który ma czwarty parametr $limit
i piąty parametr &$count
.
Łatwo jest znaleźć rozwiązanie, które zastąpi tylko pierwszą lub pierwszą parę instancji (podając wartość zliczania). Nie ma wielu rozwiązań, które mogłyby zastąpić ostatnią lub ostatnią parę instancji.
Może coś takiego jak str_replace ($ find, $ replace, $ subject, -3) powinno zastąpić ostatnie trzy instancje.
W każdym razie tylko sugestia.
s($subject)->replaceFirst($search)
is($subject)->replaceFirstIgnoreCase($search)
pomocny, jak w tej samodzielnej bibliotece .