2011-12-14 16 views
8

str_replace sostituisce tutte le occorrenze di una parola con una sostituzione.PHP str_replace() con un limite param?

preg_replace sostituisce le occorrenze di un motivo con una sostituzione e accetta un parametro di limite opzionale.

Non ho alcuna necessità di abbinamento di modelli ma vorrei la comodità di un parametro di limite. Cosa dovrei usare?

+3

stringhe sono ancora modelli, seppur semplice modelli. – Mathletics

+0

Cosa c'è che non va nell'ultimo argomento di 'str_replace'? –

+0

@Sebastien C. Tale argomento serve per ottenere il numero di sostituzioni eseguite. Ma non limita il numero di sostituzioni fatte. – DocRattie

risposta

2
function str_replace2($find, $replacement, $subject, $limit = 0){ 
    if ($limit == 0) 
    return str_replace($find, $replacement, $subject); 
    $ptn = '/' . preg_quote($find,'/') . '/'; 
    return preg_replace($ptn, $replacement, $subject, $limit); 
} 

Ciò consentirà di limitare il numero di sostituzioni. Le stringhe devono essere sottoposte a escape utilizzando preg_quote per assicurarsi che tutti i caratteri speciali non vengano interpretati come caratteri di campitura.

Demo, BTW


Nel caso in cui siete interessati, here's a version che include l'argomento &$count:

function str_replace2($find, $replacement, $subject, $limit = 0, &$count = 0){ 
    if ($limit == 0) 
    return str_replace($find, $replacement, $subject, $count); 
    $ptn = '/' . preg_quote($find,'/') . '/'; 
    return preg_replace($ptn, $replacement, $subject, $limit, $count); 
} 
+0

Lo prenderò come corretto visto che funziona per fare quello che sto cercando. Questo è vicino esattamente alla soluzione su cui mi ero stabilito, ma volevo evitare l'overhead di preg_replace, se possibile, dato che non ho bisogno di regex/pattern matching. – buley

+0

@editor: Beh, puoi scriverne uno che 'strpos' e' substr's per le corrispondenze, ma sarebbe un po 'più di lavoro (e probabilmente più veloce/fiore dato che stai facendo l'elaborazione al di fuori del motore stesso). Dipende da te, anche se sarebbe interessante vedere un confronto tra benchmark. –

+0

'$ count' dovrebbe precedere' $ limit', per essere retrocompatibile con 'str_replace()'. Inoltre, il tuo codice supporta solo le stringhe, mentre 'str_replace()' supporta gli array per '$ search',' $ replace' e '$ subject'. – 0b10011

2
$str = implode($replace, explode($search, $subject, $count + 1)); 

rapida PoC:

$str = 
"To be, or not to be, that is the question: 
Whether 'tis Nobler in the mind to suffer 
The Slings and Arrows of outrageous Fortune, 
Or to take Arms against a Sea of troubles, 
And by opposing end them"; 

/* Replace the first 2 occurrences of 'to' with 'CAN IT' in $str. */ 
echo implode('CAN IT', explode('to', $str, 3)); 

Output (enfasi aggiunta):

Per essere, o no Può essere, questo è il problema:
Sia 'più nobile nella mente PUO' soffrire
i sassi ei frecce di una sorte crudele,
O a prendere le armi contro un mare di guai,
E opponendosi finiscono loro

Si noti che questo metodo è case sensitive.

1

Originariamente tirato da https://stackoverflow.com/a/11400172/526741

ho scritto una funzione che è compatibile al 100% con str_replace(). Cioè, è possibile sostituire tutte le occorrenze distr_replace() con str_replace_limit() senza rovinare nulla fino, anche quelle che utilizzano le matrici per la $search, $replace, e/o $subject.

La funzione potrebbe essere completamente autosufficiente, se si voleva sostituire la chiamata di funzione con ($string===strval(intval(strval($string)))), ma io consiglierei di contro di essa in quanto valid_integer() è una funzione piuttosto utile quando si tratta di interi forniti come stringhe.

Nota: Quando possibile, str_replace_limit() userà str_replace() invece, in modo da tutte le chiamate a str_replace() possono essere sostituiti con str_replace_limit() senza preoccuparsi di un colpo alla performance.

utilizzo

<?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 sostituzioni - bbcbbc

$limit = 1; // Limit of 1 
$new_string = str_replace_limit($search, $replace, $subject, $count, $limit); 
echo $count.' replacements -- '.$new_string; 

1 sostituzioni - bbcabc

$limit = 10; // Limit of 10 
$new_string = str_replace_limit($search, $replace, $subject, $count, $limit); 
echo $count.' replacements -- '.$new_string; 

2 sostituzioni - bbcbbc

Funzione

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

    } 

} 
10

C'è un modo migliore per fare questo

<? 
$str = 'abcdef abcdef abcdef'; 
// pattern, replacement, string, limit 
echo preg_replace('/abc/', '123', $str, 1); // outputs '123def abcdef abcdef' 
?>