2015-06-02 144 views
3

preg_split有一個可選的PREG_SPLIT_DELIM_CAPTURE標誌,它也返回返回數組中的所有分隔符。 mb_split沒有。PHP mb_split(),捕獲分隔符

有沒有什麼辦法來拆分多字節字符串(不只是UTF-8,但所有類型)和捕獲分隔符?

我正在嘗試製作一個多字節安全的換行符,保留換行符,但希望使用更具代表性的可用解決方案。

解決方案 由於用戶卡西米爾等伊波利特,我建立了一個解決方案,並張貼在GitHub上 (https://github.com/vanderlee/PHP-multibyte-functions/blob/master/functions/mb_explode.php),這使得所有的使preg_split標誌:

/** 
* A cross between mb_split and preg_split, adding the preg_split flags 
* to mb_split. 
* @param string $pattern 
* @param string $string 
* @param int $limit 
* @param int $flags 
* @return array 
*/ 
function mb_explode($pattern, $string, $limit = -1, $flags = 0) {  
    $strlen = strlen($string);  // bytes! 
    mb_ereg_search_init($string); 

    $lengths = array(); 
    $position = 0; 
    while (($array = mb_ereg_search_pos($pattern)) !== false) { 
     // capture split 
     $lengths[] = array($array[0] - $position, false, null); 

     // move position 
     $position = $array[0] + $array[1]; 

     // capture delimiter 
     $regs = mb_ereg_search_getregs();   
     $lengths[] = array($array[1], true, isset($regs[1]) && $regs[1]); 

     // Continue on? 
     if ($position >= $strlen) { 
      break; 
     }   
    } 

    // Add last bit, if not ending with split 
    $lengths[] = array($strlen - $position, false, null); 

    // Substrings 
    $parts = array(); 
    $position = 0;  
    $count = 1; 
    foreach ($lengths as $length) { 
     $is_delimiter = $length[1]; 
     $is_captured = $length[2]; 

     if ($limit > 0 && !$is_delimiter && ($length[0] || ~$flags & PREG_SPLIT_NO_EMPTY) && ++$count > $limit) { 
      if ($length[0] > 0 || ~$flags & PREG_SPLIT_NO_EMPTY) {   
       $parts[] = $flags & PREG_SPLIT_OFFSET_CAPTURE 
          ? array(mb_strcut($string, $position), $position) 
          : mb_strcut($string, $position);     
      } 
      break; 
     } elseif ((!$is_delimiter || ($flags & PREG_SPLIT_DELIM_CAPTURE && $is_captured)) 
       && ($length[0] || ~$flags & PREG_SPLIT_NO_EMPTY)) { 
      $parts[] = $flags & PREG_SPLIT_OFFSET_CAPTURE 
         ? array(mb_strcut($string, $position, $length[0]), $position) 
         : mb_strcut($string, $position, $length[0]); 
     } 

     $position += $length[0]; 
    } 

    return $parts; 
} 
+0

你想做什麼?發佈一個示例字符串。 –

回答

2

捕獲分隔符是唯一可能與preg_split並不適用於其他功能。

那麼三種可能性:

1)您的字符串轉換爲UTF-8,使用preg_splitPREG_SPLIT_DELIM_CAPTURE,並使用array_map每個項目轉換成原始編碼。

這種方式更簡單。第二種方式並非如此。 (請注意,在一般情況下,它更簡單,在UTF8總是工作,而不是具有異國情調的編碼處理,)代替分裂樣功能,你需要使用例如mb_ereg_search_regs

2)獲得匹配的零部件,並建立這樣的模式:

delimiter|all_that_is_not_the_delimiter 

(注意交替的兩個分支必須是相互排斥的,照顧到他們寫的方式,使得結果之間是不可能的差距。第一部分必須在一開始的字符串和最後一部分必須在最後。每個部分必須是連續的到先前等等。)

3)使用mb_splitlookarounds。根據定義,lookaround是零寬度斷言,不匹配任何字符,但只匹配字符串中的位置。所以,你可以使用這種模式,經過或分隔符之前匹配的位置:

(?=delimiter)|(<=delimiter) 

(這種方式的侷限性是,在回顧後的子模式不能具有可變長度(換句話說,你不能在裏面使用量詞),但它可以是固定長度子模式的交替:(?<=subpat1|subpat2|subpat3)

+0

我想用它來分割線條上的線條。方法3表現得很好:'mb_split('(?= \ r \ n | \ r | \ n)|(<= \ r \ n | \ r | \ n)',$ text);'。謝謝! – Martijn

+0

@Martijn:如果換行符序列是'\ r \ n',這種方式將不起作用,因爲該模式將在\ r和\ n處進行分割。所以你會得到:'line','\ r','\ n','line'。方法2)在這種情況下更合適,因爲您可以簡單地使用這種模式:'[^ \ r \ n] + | \ r?\ n | \ r' –

+0

好吧,它似乎在我的測試中工作,但也有PHP 5.2和5.3拋出錯誤的問題,因爲他們認爲模式是空的。我會接下來看看你的解決方案2。 – Martijn