2011-12-14 45 views
8

str_replace thay thế tất cả các lần xuất hiện của một từ bằng một thay thế.PHP str_replace() với tham số giới hạn?

preg_replace thay thế các lần xuất hiện của mẫu có thay thế và lấy tham số giới hạn tùy chọn.

Tôi không có nhu cầu đối sánh mẫu nhưng muốn sự tiện lợi của thông số giới hạn. Tôi nên sử dụng cái gì?

+3

chuỗi vẫn là mô hình, mặc dù đơn giản mẫu. – Mathletics

+0

Có gì sai với đối số cuối cùng của 'str_replace'? –

+0

@Sebastien C. Đối số đó là để có được số lượng thay thế được thực hiện. Nhưng nó không giới hạn số lượng thay thế được thực hiện. – DocRattie

Trả lời

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

Điều đó sẽ cho phép bạn đặt giới hạn về số lượng thay thế. Chuỗi phải được thoát bằng cách sử dụng preg_quote để đảm bảo mọi ký tự đặc biệt không được hiểu là ký tự mẫu.

Demo, BTW


Trong trường hợp bạn quan tâm, here's a version bao gồm &$count luận:

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

Tôi sẽ thực hiện điều này là chính xác vì nó hoạt động để làm những gì tôi đang tìm kiếm. Điều này là gần chính xác các giải pháp mà tôi đã giải quyết trên, nhưng tôi muốn tránh chi phí preg_replace nếu có thể cho tôi không cần regex/mô hình phù hợp. – buley

+0

@editor: Vâng, bạn có thể viết một 'strpos' và' substr's cho các kết quả phù hợp, nhưng nó sẽ hoạt động nhiều hơn một chút (và cho là nhanh hơn/hoa vì bạn đang xử lý bên ngoài bản thân động cơ). Nó thuộc vào bạn, mặc dù nó sẽ là thú vị khi nhìn thấy một so sánh chuẩn. –

+0

'$ count' phải đến trước' $ limit', tương thích ngược với 'str_replace()'. Ngoài ra, mã của bạn chỉ hỗ trợ chuỗi, trong khi 'str_replace()' hỗ trợ các mảng cho '$ search',' $ replace' và '$ subject'. – 0b10011

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

nhanh 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 (nhấn mạnh thêm):

Để được, hoặc không THỂ CNTT được, đó là câu hỏi:
Cho dù 'tis cao thượng trong tâm CNTT THỂ bị
cáp treo và Mũi tên của tạp chí Fortune thái quá,
Hoặc để mất Arms chống lại một biển rắc rối,
Và bằng cách phản đối kết thúc họ

Lưu ý rằng phương pháp này phân biệt chữ hoa chữ thường.

1

Nguyên kéo từ https://stackoverflow.com/a/11400172/526741

Tôi đã viết một chức năng đó là 100% tương thích ngược với str_replace(). Tức là, bạn có thể thay thế tất cả lần xuất hiện của str_replace() với str_replace_limit() mà không làm rối loạn bất cứ thứ gì, ngay cả khi sử dụng mảng cho $search, $replace và/hoặc $subject.

Chức năng thể hoàn toàn khép kín, nếu bạn muốn thay lời gọi hàm với ($string===strval(intval(strval($string)))), nhưng tôi khuyên bạn nên chống lại nó từ valid_integer() là một chức năng khá hữu ích khi giao dịch với số nguyên được cung cấp như dây đàn.

Lưu ý: Bất cứ khi nào có thể, str_replace_limit() sẽ sử dụng str_replace() thay vào đó, vì vậy tất cả các cuộc gọi đến str_replace() có thể được thay thế bằng str_replace_limit() mà không lo lắng về một hit để thực hiện.

Cách sử dụng

<?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 thay thế - bbcbbc

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

1 thay thế - bbcabc

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

2 thay thế - bbcbbc

Chức năng

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

Theres một cách tốt hơn để làm điều này

<? 
$str = 'abcdef abcdef abcdef'; 
// pattern, replacement, string, limit 
echo preg_replace('/abc/', '123', $str, 1); // outputs '123def abcdef abcdef' 
?> 
Các vấn đề liên quan