Verwenden Sie str_replace, damit es nur beim ersten Match wirkt?
325
Ich möchte eine Version davon str_replace(), die nur das erste Auftreten von $searchin der ersetzt $subject. Gibt es eine einfache Lösung dafür oder brauche ich eine hackige Lösung?
Der Nachteil dieser Methode ist die Leistungsbeeinträchtigung durch reguläre Ausdrücke.
Zombat
27
Ein weiterer Nachteil ist, dass Sie preg_quote () für die "Nadel" verwenden und die Metazeichen $ und \ im Ersatz maskieren müssen.
Josh Davis
32
Dies schlägt als generische Lösung aufgrund böser Probleme fehl.
Jeremy Kauffman
2
Viel zu oft werden reguläre Ausdrücke aufgrund von "Leistung" verworfen. Wenn Leistung das Hauptanliegen wäre, würden wir kein PHP schreiben! Etwas anderes als '/' könnte verwendet werden, um das Muster zu verpacken, vielleicht '~', was helfen würde, das entweichende Problem bis zu einem gewissen Grad zu vermeiden. Es kommt darauf an, was die Daten sind und woher sie stammen.
Thomas Redstone
1
Abgesehen von Leistungseinbußen - haben diejenigen, die sich über Probleme beschweren, etwas Besonderes im Sinn, abgesehen von potenziellen Fehlern preg_quote? Zum Beispiel befürchtet @ThomasRedstone, dass das Trennzeichen /gefährlich sein könnte, wenn es in angezeigt wird $from, aber zum Glück nicht: Es wird aufgrund des preg_quotezweiten Parameters ordnungsgemäß maskiert (das kann man leicht testen). Ich würde gerne etwas über bestimmte Probleme erfahren (die in meinem Buch schwerwiegende PCRE-Sicherheitslücken darstellen würden).
MvanGeest
609
Es gibt keine Version davon, aber die Lösung ist überhaupt nicht hackig.
Kann viel schneller sein und benötigt weniger Speicher als reguläre Ausdrücke. Keine Ahnung, warum jemand das ablehnen würde ...
Josh Davis
12
Ich mag diesen Ansatz, aber der Code hat einen Fehler. Der letzte Parameter des Aufrufs von substr_replace sollte strlen ($adel) anstelle von strlen ($ replace) sein. Bitte beachten Sie dies!
Nelson
Es ist "hacky" in dem Sinne, dass es erheblich länger dauert, um herauszufinden, was los ist. Auch wenn es sich um klaren Code handelte, wäre nicht erwähnt worden, dass der Code einen Fehler aufweist. Wenn es möglich ist, in einem so kleinen Ausschnitt einen Fehler zu machen, ist es schon viel zu hackig.
Camilo Martin
9
Ich bin mit @CamiloMartin in Bezug auf die Anzahl der Zeilen im Vergleich zur Möglichkeit von Fehlern nicht einverstanden. Obwohl substr_replacees sich aufgrund aller Parameter um eine etwas unhandliche Funktion handelt, besteht das eigentliche Problem darin, dass die Manipulation von Zeichenfolgen durch Zahlen manchmal nur schwierig ist. Sie müssen darauf achten, die richtige Variable / den richtigen Offset an die Funktionen zu übergeben. Ich würde sogar so weit gehen zu sagen, dass der obige Code der einfachste und für mich logischste Ansatz ist.
Alex
1
Genialer Ansatz. Funktioniert perfekt, wenn Variablenwerte ersetzt werden, in denen Regex-Zeichen reserviert sind (preg_replace ist also bear). Das ist unkompliziert und elegant.
Praesagus
96
Bearbeiten: Beide Antworten wurden aktualisiert und sind jetzt korrekt. Ich werde die Antwort hinterlassen, da die Funktionszeiten immer noch nützlich sind.
Die Antworten von 'zombat' und 'too much php' sind leider nicht korrekt. Dies ist eine Überarbeitung der Antwort von zombat (da ich nicht genug Ruf habe, um einen Kommentar zu schreiben):
Beachten Sie die Strlen ($ Nadel) anstelle von Strlen ($ Ersetzen). Das Beispiel von Zombat funktioniert nur dann korrekt, wenn Nadel und Ersatz dieselbe Länge haben.
Hier ist die gleiche Funktionalität in einer Funktion mit der gleichen Signatur wie PHPs eigener str_replace:
Dies ist die überarbeitete Antwort von 'zu viel PHP':
implode($replace, explode($search, $subject,2));
Beachten Sie die 2 am Ende anstelle von 1. Oder im Funktionsformat:
function str_replace_first($search, $replace, $subject){return implode($replace, explode($search, $subject,2));}
Ich habe die beiden Funktionen zeitlich festgelegt und die erste ist doppelt so schnell, wenn keine Übereinstimmung gefunden wird. Sie haben die gleiche Geschwindigkeit, wenn eine Übereinstimmung gefunden wird.
Warum generifizieren Sie dies nicht wie folgt: str_replace_flexible (gemischte $ s, gemischte $ r, int $ Offset, int $ Limit), wobei die Funktion $ limit Vorkommen ab dem $ offset (n-ten) Match ersetzt.
Adam Friedman
Schade, dass dies nur für Groß- und Kleinschreibung gilt.
Vielen Dank dafür, ich verwende im Allgemeinen preg_replace, da es am flexibelsten ist, wenn zukünftige Optimierungen in den meisten Fällen erforderlich sind. 27% langsamer werden nicht signifikant sein
zzapper
@oLinkWebDevelopment Ich würde gerne Ihr Benchmark-Skript sehen. Ich denke, es könnte sich als nützlich erweisen.
Dave Morton
Der Grund, warum substr_replace()das Ergebnis gewonnen wird, ist einfach; weil es eine interne Funktion ist. Zwei interne und benutzerdefinierte Funktionen, die dasselbe tun, unterscheiden sich in der Leistung, da die interne Funktion in niedrigeren Ebenen ausgeführt wird. Warum also nicht preg_match()? Reguläre Ausdrücke sind fast langsamer als jede interne String-Manipulationsfunktion, da sie mehrmals in einem String suchen.
MAChitgarha
1
Ich hoffe, dass der Benchmark für Ihren "Gewinner" ( substr_replace($string, $replace, 0, strlen($search));) nicht nur diese Statik geschrieben hat 0. Ein Teil der Faltung von Nicht-Regex-Lösungen besteht darin, dass sie den Ausgangspunkt "finden" müssen, bevor sie wissen, wo sie ersetzt werden müssen.
Mickmackusa
55
Leider kenne ich keine PHP-Funktion, die dies kann.
Sie können Ihre eigenen ziemlich einfach so rollen:
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 $replacereturn implode($replace, explode($find, $subject,2));}
Ich habe diese kleine Funktion erstellt, die String für String (Groß- und Kleinschreibung beachten) durch Limit ersetzt, ohne dass Regexp erforderlich ist. Es funktioniert gut.
$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
Obwohl ich es lieber tun ===falsewürde is_bool(, als expliziter zu sein - ich gebe diesen Daumen auf, nur weil er den RegExp-Wahnsinn vermieden hat ! ... und gleichzeitig funktioniert es und saubere Lösung ...
jave.web
Eine leicht anpassbare preg_Lösung zu bevorzugen, ist kein Wahnsinn, sondern eine persönliche Präferenz. return preg_replace('/'.preg_quote($search, '/').'/', $replace, $content, 1);ist ziemlich einfach zu lesen für Leute, die keine Angst vor Regex haben. Benötigen Sie eine Suche ohne Berücksichtigung der Groß- und Kleinschreibung? Fügen Sie inach dem Ende Muster - Begrenzung. Benötigen Sie Unicode / Multibyte-Unterstützung? Fügen Sie unach dem Ende Muster - Begrenzung. Benötigen Sie Unterstützung für Wortgrenzen? Fügen Sie \bauf beiden Seiten Ihrer Suchzeichenfolge hinzu. Wenn Sie keinen regulären Ausdruck wünschen, verwenden Sie keinen regulären Ausdruck. Pferde für Kurse, aber sicher kein Wahnsinn.
Mickmackusa
3
Am einfachsten wäre es, reguläre Ausdrücke zu verwenden.
Die andere Möglichkeit besteht darin, die Position des Strings mit strpos () und dann mit substr_replace () zu ermitteln.
Aber ich würde mich wirklich für die RegExp entscheiden.
Schlägt fehl, wenn $ dies Zeichen wie aaa vs aaaaaaaaa
Cristo
Ich denke das sollte substr($where,$b+strlen($this))nicht sein substr($where,$b+1). Und ich denke das substr_replaceist schneller.
Titus
Code wurde überarbeitet, jetzt funktioniert es auch für lange Saiten
PYK
Diese Lösung funktioniert nicht wie codiert. Beweis: 3v4l.org/cMeZj Und wenn Sie das Problem mit der Benennung von Variablen beheben, funktioniert es nicht, wenn der Suchwert nicht gefunden wird - es beschädigt die Eingabezeichenfolge. Beweis: 3v4l.org/XHtfc
mickmackusa
Ist es fair für jemanden, der den Code FIXIEREN möchte? @mickmackusa Kannst du das bitte nochmal überprüfen?
PYK
2
$string ='this is my world, not my world';
$find ='world';
$replace ='farm';
$result = preg_replace("/$find/",$replace,$string,1);
echo $result;
Dies ist genau das gleiche wie die erste Antwort. Außerdem sollten Sie ein preg_quotevon ausführen, $findbevor Sie es als Ausdruck verwenden.
Emil Vikström
Das habe ich benutzt, also habe ich es hochgestimmt. Die erste Antwort verursachte einen Konflikt mit Drupal. Sie muss eine Drupal-Hilfsfunktion überschrieben haben. Also habe ich einfach den Code genommen, der sich in der Funktion befand, und ihn in Übereinstimmung mit dem Rest des Codes verwendet ...
Dan Mantyla
Diese Nur-Code-Antwort bietet redundante Ratschläge auf der Seite (ganz zu schweigen davon, dass sie fehlen preg_quote(). Diese späte doppelte Antwort kann sicher von der Seite gelöscht werden, da ihre Ratschläge von der früheren und höher bewerteten akzeptierten Antwort bereitgestellt werden.
mickmackusa
2
Um die Antwort von @ renocor zu erweitern , habe ich eine Funktion geschrieben, die zu 100% abwärtskompatibel ist str_replace(). Das heißt, Sie ersetzen können alle Vorkommen str_replace()mit , str_replace_limit()ohne etwas durcheinander, auch die Verwendung von Arrays für die $search, $replaceund / oder $subject.
Die Funktion könnte vollständig in sich geschlossen sein, wenn Sie den Funktionsaufruf durch ersetzen möchten ($string===strval(intval(strval($string)))), aber ich würde dagegen empfehlen, da dies valid_integer()eine ziemlich nützliche Funktion ist, wenn Sie Ganzzahlen verwenden, die als Zeichenfolgen bereitgestellt werden.
Hinweis: Wann immer möglich, str_replace_limit()wird str_replace()stattdessen verwendet, sodass alle Anrufe an str_replace()durch ersetzt werden können, str_replace_limit()ohne sich um einen Leistungseinbruch sorgen zu müssen.
<?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 -1if($limit!=-1){
$limit -= $this_count;}// Reached $limit, return $subjectif($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 -1if($limit!=-1){
$limit -= $this_count;}// Reached $limit, return $subjectif($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 foundif($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 reachedfor($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 $needleif($pos===false){break;}}// Return new $subjectreturn $subject;}}
ein bisschen aufgebläht, wenn du mich fragst. Was ich an dieser Lösung am meisten "hasse", ist auch die Fehlerbehandlung. Es bricht das Skript, wenn Sie falsche Werte übergeben. Sie denken, es sieht professionell aus, aber es ist nicht so, dass Sie anstelle eines Fehlers stattdessen einen Hinweis oder eine Warnung erstellen. Besser ist es, den Bullshit zu überspringen, stattdessen false oder null zurückzugeben und in einer solchen Funktion niemals eine Rückverfolgung zu verwenden. Die beste Lösung ist, dass der Programmierer entscheiden kann, was zu tun ist, wenn die Ausgabe falsch / unerwartet ist.
Codebeat
@Erwinus Diese nutzt im E_USER_WARNINGgesamten Gebäude , das eine ist Warnung , nicht ein Fehler . Die Rückverfolgung ist äußerst nützlich, um herauszufinden, welcher Code die ungültigen Daten überhaupt an die Funktion weitergibt (was unbedingt erforderlich ist, um Fehler in der Produktion aufzuspüren). Wie bei der Rückkehr $subjectstatt false/ nulloder einen Fehler zu werfen, die einfach eine persönliche Entscheidung für meinen Anwendungsfall war. Um mit str_replace()der Funktionalität übereinzustimmen, ist es am besten, abfangbare schwerwiegende Fehler zu verwenden (wie dies auch der str_replace()Fall ist, wenn die ersten beiden Argumente geschlossen werden).
0b10011
Ah, ich habe nichts von der E_USER_WARNING bemerkt, die Sie verwenden. Tut mir leid. Das Problem bei der Rückgabe des Betreffs ist, dass Sie nie sehen können, dass außerhalb der Funktion etwas nicht stimmt. Das heißt, die Funktion kann halb so groß sein, wenn Sie es intelligenter machen (es ist möglich). Zweitens sind Kommentare in Ordnung, wenn sie etwas Komplexes erklären, aber für einfache Dinge wie die Wertsteigerung nicht sehr nützlich sind. Insgesamt halte ich es für unnötig groß. Die Verwendung von Warnungen in einer Produktionsumgebung kann auch ein Sicherheitsproblem darstellen, wenn Sie diesen Code auf einem Server verwenden, der Laufzeitnachrichten standardmäßig nicht unterdrückt (Protokolle).
Codebeat
@Erwinus Ich war ausführlich, wenn es um die Kommentare ging, weil einige Leute die Sprache nicht so gut verstehen wie andere, und Kommentare können immer von denen entfernt werden, die sie verstehen. Wenn Sie einen besseren Weg kennen, um für alle Randfälle das gleiche Endergebnis zu erzielen, bearbeiten Sie auf jeden Fall die Antwort. Und wenn Ihre Produktionsumgebung keine Fehlermeldungen unterdrückt, haben Sie ein größeres Problem als diese Funktion;)
0b10011
TL; DR Dieses Snippet ist so aufgebläht, dass ich mir nicht vorstellen kann, es einer Regex-Funktion vorzuziehen (ich hasse es zu scrollen). Wenn Sie die vorgenommenen Ersetzungen zählen möchten, gibt es dafür einen Parameter in preg_replace(). Darüber hinaus bietet preg_replace()/ regex die Behandlung von Wortgrenzen (falls gewünscht) - etwas, das Nicht-Regex-Funktionen nicht elegant bieten.
Mickmackusa
2
Nach meinem Testergebnis möchte ich den von karim79 bereitgestellten regulären_Ausdruck abstimmen. (Ich habe nicht genug Ruf, um jetzt darüber abzustimmen!)
Die Lösung von zombat verwendet zu viele Funktionsaufrufe, ich vereinfache sogar die Codes. Ich verwende PHP 5.4, um beide Lösungen 100.000 Mal auszuführen, und hier ist das Ergebnis:
$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
Wie du siehst. Die Leistung von preg_replace ist nicht so schlecht, wie viele Leute denken. Daher würde ich die klassische Lösung vorschlagen, wenn Ihr regulärer Express nicht kompliziert ist.
Ihr erstes Snippet ist ein unfairer Vergleich, da es keine korrekte Implementierung verwendet. Sie suchen nicht $posnach false. Wenn die Nadel also nicht im Heuhaufen vorhanden ist, wird die Ausgabe beschädigt.
Mickmackusa
Danke @mickmackusa, du hast recht. Aber darum geht es nicht. Ich sagte, dieser Code sei vereinfacht, um die Effizienz von Implementierungen zu vergleichen.
Hunter Wu
Das ist genau mein Punkt. Sie dürfen niemals Benchmark-Vergleiche durchführen, die nicht genau denselben Prozess ausführen. Der Vergleich von Äpfeln mit Halborangen ist nicht sinnvoll. Durch die vollständige Implementierung des vollständigen Nicht-Regex-Ansatzes wird der Geschwindigkeitsunterschied noch größer.
Mickmackusa
Nochmals vielen Dank. Ich möchte jedoch die bessere Implementierung finden und keinen tiefgreifenden Unterschied machen.
Hunter Wu
2
Um die Antwort von zombat (die meiner Meinung nach die beste Antwort ist) zu erweitern, habe ich eine rekursive Version seiner Funktion erstellt, die einen $limitParameter enthält, der angibt, wie viele Vorkommen Sie ersetzen möchten.
Beachten Sie, dass keine Qualitätsprüfung aktiviert $start_posist. Wenn die Zeichenfolgenlänge überschritten wird, generiert diese Funktion : Warning: strpos(): Offset not contained in string.... Diese Funktion kann nicht ersetzt werden, wenn die $start_posLänge überschritten wird. Fehlernachweis: 3v4l.org/qGuVIR ... Ihre Funktion kann die return $haystackBedingungen kombinieren und vermeiden, Einwegvariablen wie diese zu deklarieren : 3v4l.org/Kdmqp Wie ich jedoch in den Kommentaren an anderer Stelle auf dieser Seite gesagt habe, würde ich es vorziehen Verwenden Sie einen sehr sauberen, direkten, nicht rekursiven preg_replace()Aufruf.
Mickmackusa
Ja, damit Sie diese Zeile elsehinzufügen können$start_pos > strlen($haystack) ? $start_pos = strlen($haystack) : '';
Manojkiran.A
2
Für eine Zeichenfolge
$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
Für ein einzelnes Zeichen
$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
Das erste substr_replace () - Snippet schlägt fehl, wenn sich die Suchzeichenfolge nicht am Offset 0 der Eingabezeichenfolge befindet. Fehlernachweis : 3v4l.org/oIbRv Beide substr_replace()Techniken beschädigen die Eingabezeichenfolge, wenn der Suchwert nicht vorhanden ist. Beweis des Scheiterns: 3v4l.org/HmEml (Und diese letzte Technik mit allen revAnrufen ist ernsthaft verworren / hart für die Augen.)
mickmackusa
2
Denken Sie daran, dass die gesamte Zeichenfolge ein Array ist:
$string ="Lorem ipsum lá lá lá";
$string[0]="B";
echo $string;
Es sei denn, es enthält Multibyte-Zeichen ... und dann schlägt Ihre Technik fehl. Wie bedauerlich, dass Sie eine Beispiel-Eingabezeichenfolge mit angeboten haben á. Demonstration des Scheiterns
mickmackusa
Sie können überprüfen, ob stringes sich um eine Multibyte-Zeichenfolge handelt, indem Siemb_strlen($subject) != strlen($subject)
RousseauAlexandre
Dieser Beitrag versucht nicht, die gestellte Frage zu beantworten.
Mit substr_replace können wir das Auftreten des ersten Zeichens nur in einer Zeichenfolge ersetzen. wie & wird mehrmals wiederholt, aber nur an der ersten Position müssen wir & durch ersetzen?
Wenn das die Ausgabe ist, worum geht es dann? Sollte es nicht nur das erste Kleinbuchstaben "z" durch ein Großbuchstaben "Z" ersetzen? Anstatt alle zu ersetzen? Ich dachte, das war es, worüber wir hier sprachen ...
Swivel
Mein schlechtes, es wird nur das erste Vorkommen ersetzen. Bearbeitet.
happyhardik
Der gleiche Rat wurde bereits fast drei Jahre zuvor von Bas angeboten (und ohne übermäßig anzurufen strpos()). Heruntergestuft, da der Seite kein neuer Wert hinzugefügt wird.
Mickmackusa
0
Wenn Ihre Zeichenfolge keine Multibyte-Zeichen enthält und Sie nur ein Zeichen ersetzen möchten, können Sie sie einfach verwenden strpos
Hier eine Funktion, die Fehler behandelt
/**
* 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 paramsif(strlen($replace)!=1|| strlen($search)!=1){thrownewInvalidArgumentException('$search & $replace must be char');}elseif(mb_strlen($subject)!= strlen($subject)){thrownewInvalidArgumentException('$subject is an multibytes string');}// search
$pos = strpos($subject, $search);if($pos ===false){// not foundreturn $subject;}// replace
$subject[$replace]= $subject;return $subject;}
Hier ist eine einfache Klasse, die ich erstellt habe, um unsere leicht modifizierten Funktionen str_replace () zu verpacken .
Mit unserer Funktion php :: str_rreplace () können Sie auch einen umgekehrten, begrenzten str_replace () ausführen, was sehr praktisch sein kann, wenn Sie versuchen, nur die letzten X-Instanzen eines Strings zu ersetzen.
<?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
*/publicstaticfunction 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
*/publicstaticfunction str_rreplace($find, $replace, $subject, $replacement_limit =-1){return strrev(self::str_replace(strrev($find), strrev($replace), strrev($subject), $replacement_limit));}}
Ihr Beitrag bietet keinen Mehrwert für diese bereits überfüllte Seite. Ihre Regex-Lösung schlägt in vielen Randfällen fehl, weil Sie das falsche Werkzeug verwendet haben, um Zeichen in der Nadelkette zu maskieren. Fehlernachweis : 3v4l.org/dTdYK Die stark positiv bewertete und akzeptierte Antwort aus dem Jahr 2009 zeigt bereits die ordnungsgemäße Ausführung dieser Technik. Ihre zweite Methode beantwortet die gestellte Frage nicht und wurde bereits von oLinkWebDevelopment bereitgestellt.
Diese Technik wurde 2009 von toomuchphp zur Verfügung gestellt ! Ich habe abgelehnt, weil Ihr Beitrag den Forschern keinen neuen Wert verleiht. Stellen Sie vor dem Veröffentlichen einer Antwort sicher, dass Ihre Lösung für die Seite eindeutig ist und der Seite einen Mehrwert verleiht.
Mickmackusa
-3
Dies ist meine erste Antwort hier, ich hoffe es richtig zu machen. Warum nicht das vierte Argument der Funktion str_replace für dieses Problem verwenden?
count: Wenn bestanden, wird dies auf die Anzahl der durchgeführten Ersetzungen gesetzt.
edit: Diese Antwort ist falsch, da der 4. Parameter von str_replace eine Variable ist, der die Anzahl der durchgeführten Ersetzungen zugewiesen wird. Dies ist nicht konsistent mit preg_replace , das einen 4. Parameter $limitund einen 5. Parameter hat &$count.
Die vierten Argumente werden von str_replace () auf die Anzahl der vorgenommenen Ersetzungen gesetzt. Aus diesem Grund erhalten Sie eine Fehlermeldung, wenn Sie eine Ganzzahl und keine Variable übergeben.
Arminrosu
-6
Es ist einfach, eine Lösung zu finden, um nur die ersten oder ersten Instanzen zu ersetzen (indem Sie den Zählwert angeben). Es gibt nicht viele Lösungen, um die letzten oder letzten Instanzen zu ersetzen.
Vielleicht sollte so etwas wie str_replace ($ find, $ replace, $ subject, -3) die letzten drei Instanzen ersetzen.
Warum eine Frage mit einem Vorschlag beantworten, wenn eine Antwort zwei Jahre zuvor angenommen wurde?!
mbinette
Auch -3 funktioniert nicht als Parameter, da der 4. Parameter ausgegeben und kein Eingabeparameter ist. Es wäre besser, wenn Sie testen, was Sie vorschlagen, anstatt einen Code zu veröffentlichen, der abstürzt.
Ghostwriter78
Ja, das ist falsch, aber warum bekomme ich einen Absturz auf einem leeren Bildschirm, wenn ich es versuche? Ich habe die übliche Fehlerberichterstattung (E_ALL) durchgeführt. ini_set ("display_errors", 1); Immer noch leerer Bildschirmfehler.
s($subject)->replaceFirst($search)
unds($subject)->replaceFirstIgnoreCase($search)
hilfreich, wie in dieser eigenständigen Bibliothek gefunden .Antworten:
Kann mit preg_replace durchgeführt werden :
Die Magie liegt im optionalen vierten Parameter [Limit]. Aus der Dokumentation:
Obwohl finden Sie zombat Antwort für eine effizientere Methode (grob, 3-4x schneller).
quelle
preg_quote
? Zum Beispiel befürchtet @ThomasRedstone, dass das Trennzeichen/
gefährlich sein könnte, wenn es in angezeigt wird$from
, aber zum Glück nicht: Es wird aufgrund despreg_quote
zweiten Parameters ordnungsgemäß maskiert (das kann man leicht testen). Ich würde gerne etwas über bestimmte Probleme erfahren (die in meinem Buch schwerwiegende PCRE-Sicherheitslücken darstellen würden).Es gibt keine Version davon, aber die Lösung ist überhaupt nicht hackig.
Ziemlich einfach und spart die Leistungseinbußen bei regulären Ausdrücken.
Bonus: Wenn Sie das letzte Vorkommen ersetzen möchten , verwenden Sie es einfach
strrpos
anstelle vonstrpos
.quelle
substr_replace
es sich aufgrund aller Parameter um eine etwas unhandliche Funktion handelt, besteht das eigentliche Problem darin, dass die Manipulation von Zeichenfolgen durch Zahlen manchmal nur schwierig ist. Sie müssen darauf achten, die richtige Variable / den richtigen Offset an die Funktionen zu übergeben. Ich würde sogar so weit gehen zu sagen, dass der obige Code der einfachste und für mich logischste Ansatz ist.Bearbeiten: Beide Antworten wurden aktualisiert und sind jetzt korrekt. Ich werde die Antwort hinterlassen, da die Funktionszeiten immer noch nützlich sind.
Die Antworten von 'zombat' und 'too much php' sind leider nicht korrekt. Dies ist eine Überarbeitung der Antwort von zombat (da ich nicht genug Ruf habe, um einen Kommentar zu schreiben):
Beachten Sie die Strlen ($ Nadel) anstelle von Strlen ($ Ersetzen). Das Beispiel von Zombat funktioniert nur dann korrekt, wenn Nadel und Ersatz dieselbe Länge haben.
Hier ist die gleiche Funktionalität in einer Funktion mit der gleichen Signatur wie PHPs eigener str_replace:
Dies ist die überarbeitete Antwort von 'zu viel PHP':
Beachten Sie die 2 am Ende anstelle von 1. Oder im Funktionsformat:
Ich habe die beiden Funktionen zeitlich festgelegt und die erste ist doppelt so schnell, wenn keine Übereinstimmung gefunden wird. Sie haben die gleiche Geschwindigkeit, wenn eine Übereinstimmung gefunden wird.
quelle
stripos()
zur Rettung :-)Ich habe mich gefragt, welches das schnellste ist, also habe ich sie alle getestet.
Unten finden Sie:
Alle Funktionen wurden mit den gleichen Einstellungen getestet:
Funktionen, die nur das erste Auftreten einer Zeichenfolge innerhalb einer Zeichenfolge ersetzen :
substr_replace($string, $replace, 0, strlen($search));
replace_first($search, $replace, $string);
preg_replace($search, $replace, $string, 1);
str_replace_once($search, $replace, $string);
str_replace_limit($search, $replace, $string, $count, 1);
str_replace_limit($search, $replace, $string, 1);
str_replace_limit($string, $search, $replace, 1, 0);
Funktionen, die nur das letzte Vorkommen einer Zeichenfolge innerhalb einer Zeichenfolge ersetzen :
substr_replace($string, $replace, strrpos($string, $search), strlen($search));
strrev(implode(strrev($replace), explode(strrev($search), strrev($string), 2)));
quelle
substr_replace()
das Ergebnis gewonnen wird, ist einfach; weil es eine interne Funktion ist. Zwei interne und benutzerdefinierte Funktionen, die dasselbe tun, unterscheiden sich in der Leistung, da die interne Funktion in niedrigeren Ebenen ausgeführt wird. Warum also nichtpreg_match()
? Reguläre Ausdrücke sind fast langsamer als jede interne String-Manipulationsfunktion, da sie mehrmals in einem String suchen.substr_replace($string, $replace, 0, strlen($search));
) nicht nur diese Statik geschrieben hat0
. Ein Teil der Faltung von Nicht-Regex-Lösungen besteht darin, dass sie den Ausgangspunkt "finden" müssen, bevor sie wissen, wo sie ersetzt werden müssen.Leider kenne ich keine PHP-Funktion, die dies kann.
Sie können Ihre eigenen ziemlich einfach so rollen:
quelle
join
stattimplode
.return implode($replace, explode($find, $subject, $limit+1));
für benutzerdefinierteIch habe diese kleine Funktion erstellt, die String für String (Groß- und Kleinschreibung beachten) durch Limit ersetzt, ohne dass Regexp erforderlich ist. Es funktioniert gut.
Anwendungsbeispiel:
quelle
===false
würdeis_bool(
, als expliziter zu sein - ich gebe diesen Daumen auf, nur weil er den RegExp-Wahnsinn vermieden hat ! ... und gleichzeitig funktioniert es und saubere Lösung ...preg_
Lösung zu bevorzugen, ist kein Wahnsinn, sondern eine persönliche Präferenz.return preg_replace('/'.preg_quote($search, '/').'/', $replace, $content, 1);
ist ziemlich einfach zu lesen für Leute, die keine Angst vor Regex haben. Benötigen Sie eine Suche ohne Berücksichtigung der Groß- und Kleinschreibung? Fügen Siei
nach dem Ende Muster - Begrenzung. Benötigen Sie Unicode / Multibyte-Unterstützung? Fügen Sieu
nach dem Ende Muster - Begrenzung. Benötigen Sie Unterstützung für Wortgrenzen? Fügen Sie\b
auf beiden Seiten Ihrer Suchzeichenfolge hinzu. Wenn Sie keinen regulären Ausdruck wünschen, verwenden Sie keinen regulären Ausdruck. Pferde für Kurse, aber sicher kein Wahnsinn.Am einfachsten wäre es, reguläre Ausdrücke zu verwenden.
Die andere Möglichkeit besteht darin, die Position des Strings mit strpos () und dann mit substr_replace () zu ermitteln.
Aber ich würde mich wirklich für die RegExp entscheiden.
quelle
quelle
=> CODE WURDE ÜBERARBEITET, daher sollten einige Kommentare zu alt sein
Also los geht's für:
Ersetzen des ersten 'o' durch 'ea' zum Beispiel:
Die Funktion:
quelle
substr($where,$b+strlen($this))
nicht seinsubstr($where,$b+1)
. Und ich denke dassubstr_replace
ist schneller.quelle
preg_quote
von ausführen,$find
bevor Sie es als Ausdruck verwenden.preg_quote()
. Diese späte doppelte Antwort kann sicher von der Seite gelöscht werden, da ihre Ratschläge von der früheren und höher bewerteten akzeptierten Antwort bereitgestellt werden.Um die Antwort von @ renocor zu erweitern , habe ich eine Funktion geschrieben, die zu 100% abwärtskompatibel ist
str_replace()
. Das heißt, Sie ersetzen können alle Vorkommenstr_replace()
mit ,str_replace_limit()
ohne etwas durcheinander, auch die Verwendung von Arrays für die$search
,$replace
und / oder$subject
.Die Funktion könnte vollständig in sich geschlossen sein, wenn Sie den Funktionsaufruf durch ersetzen möchten
($string===strval(intval(strval($string))))
, aber ich würde dagegen empfehlen, da diesvalid_integer()
eine ziemlich nützliche Funktion ist, wenn Sie Ganzzahlen verwenden, die als Zeichenfolgen bereitgestellt werden.Hinweis: Wann immer möglich,
str_replace_limit()
wirdstr_replace()
stattdessen verwendet, sodass alle Anrufe anstr_replace()
durch ersetzt werden können,str_replace_limit()
ohne sich um einen Leistungseinbruch sorgen zu müssen.Verwendungszweck
Funktion
quelle
E_USER_WARNING
gesamten Gebäude , das eine ist Warnung , nicht ein Fehler . Die Rückverfolgung ist äußerst nützlich, um herauszufinden, welcher Code die ungültigen Daten überhaupt an die Funktion weitergibt (was unbedingt erforderlich ist, um Fehler in der Produktion aufzuspüren). Wie bei der Rückkehr$subject
stattfalse
/null
oder einen Fehler zu werfen, die einfach eine persönliche Entscheidung für meinen Anwendungsfall war. Um mitstr_replace()
der Funktionalität übereinzustimmen, ist es am besten, abfangbare schwerwiegende Fehler zu verwenden (wie dies auch derstr_replace()
Fall ist, wenn die ersten beiden Argumente geschlossen werden).preg_replace()
. Darüber hinaus bietetpreg_replace()
/ regex die Behandlung von Wortgrenzen (falls gewünscht) - etwas, das Nicht-Regex-Funktionen nicht elegant bieten.Nach meinem Testergebnis möchte ich den von karim79 bereitgestellten regulären_Ausdruck abstimmen. (Ich habe nicht genug Ruf, um jetzt darüber abzustimmen!)
Die Lösung von zombat verwendet zu viele Funktionsaufrufe, ich vereinfache sogar die Codes. Ich verwende PHP 5.4, um beide Lösungen 100.000 Mal auszuführen, und hier ist das Ergebnis:
==> 1,85 Sek
==> 1,35 Sek
Wie du siehst. Die Leistung von preg_replace ist nicht so schlecht, wie viele Leute denken. Daher würde ich die klassische Lösung vorschlagen, wenn Ihr regulärer Express nicht kompliziert ist.
quelle
$pos
nachfalse
. Wenn die Nadel also nicht im Heuhaufen vorhanden ist, wird die Ausgabe beschädigt.Um die Antwort von zombat (die meiner Meinung nach die beste Antwort ist) zu erweitern, habe ich eine rekursive Version seiner Funktion erstellt, die einen
$limit
Parameter enthält, der angibt, wie viele Vorkommen Sie ersetzen möchten.quelle
$start_pos
ist. Wenn die Zeichenfolgenlänge überschritten wird, generiert diese Funktion :Warning: strpos(): Offset not contained in string...
. Diese Funktion kann nicht ersetzt werden, wenn die$start_pos
Länge überschritten wird. Fehlernachweis: 3v4l.org/qGuVIR ... Ihre Funktion kann diereturn $haystack
Bedingungen kombinieren und vermeiden, Einwegvariablen wie diese zu deklarieren : 3v4l.org/Kdmqp Wie ich jedoch in den Kommentaren an anderer Stelle auf dieser Seite gesagt habe, würde ich es vorziehen Verwenden Sie einen sehr sauberen, direkten, nicht rekursivenpreg_replace()
Aufruf.else
hinzufügen können$start_pos > strlen($haystack) ? $start_pos = strlen($haystack) : '';
Für eine Zeichenfolge
Für ein einzelnes Zeichen
quelle
substr_replace()
Techniken beschädigen die Eingabezeichenfolge, wenn der Suchwert nicht vorhanden ist. Beweis des Scheiterns: 3v4l.org/HmEml (Und diese letzte Technik mit allenrev
Anrufen ist ernsthaft verworren / hart für die Augen.)Denken Sie daran, dass die gesamte Zeichenfolge ein Array ist:
"Borem ipsum lá lá lá"
quelle
á
. Demonstration des Scheiternsstring
es sich um eine Multibyte-Zeichenfolge handelt, indem Siemb_strlen($subject) != strlen($subject)
Mit substr_replace können wir das Auftreten des ersten Zeichens nur in einer Zeichenfolge ersetzen. wie & wird mehrmals wiederholt, aber nur an der ersten Position müssen wir & durch ersetzen?
quelle
Diese Funktion ist stark von der Antwort von @renocor inspiriert. Es macht die Funktion Multi-Byte-sicher.
quelle
Sie können dies verwenden:
Fand dieses Beispiel von php.net
Verwendungszweck:
Ausgabe:
Dies kann die Leistung ein wenig verringern, ist aber die einfachste Lösung.
quelle
strpos()
). Heruntergestuft, da der Seite kein neuer Wert hinzugefügt wird.Wenn Ihre Zeichenfolge keine Multibyte-Zeichen enthält und Sie nur ein Zeichen ersetzen möchten, können Sie sie einfach verwenden
strpos
Hier eine Funktion, die Fehler behandelt
quelle
Für Schleifenlösung
quelle
Hier ist eine einfache Klasse, die ich erstellt habe, um unsere leicht modifizierten Funktionen str_replace () zu verpacken .
Mit unserer Funktion php :: str_rreplace () können Sie auch einen umgekehrten, begrenzten str_replace () ausführen, was sehr praktisch sein kann, wenn Sie versuchen, nur die letzten X-Instanzen eines Strings zu ersetzen.
Diese Beispiele verwenden beide preg_replace () .
quelle
Es gibt noch einen zusätzlichen Speicherplatz, aber es spielte keine Rolle, da es sich in meinem Fall um ein Backgound-Skript handelte.
quelle
Dies ist meine erste Antwort hier, ich hoffe es richtig zu machen. Warum nicht das vierte Argument der Funktion str_replace für dieses Problem verwenden?
edit: Diese Antwort ist falsch, da der 4. Parameter von str_replace eine Variable ist, der die Anzahl der durchgeführten Ersetzungen zugewiesen wird. Dies ist nicht konsistent mit preg_replace , das einen 4. Parameter
$limit
und einen 5. Parameter hat&$count
.quelle
Es ist einfach, eine Lösung zu finden, um nur die ersten oder ersten Instanzen zu ersetzen (indem Sie den Zählwert angeben). Es gibt nicht viele Lösungen, um die letzten oder letzten Instanzen zu ersetzen.
Vielleicht sollte so etwas wie str_replace ($ find, $ replace, $ subject, -3) die letzten drei Instanzen ersetzen.
Jedenfalls nur ein Vorschlag.
quelle