2010-02-04 68 views
40

我怎麼能爆炸以下字符串:PHP爆炸的字符串,但對待引號的話作爲一個單詞

Lorem ipsum "dolor sit amet" consectetur "adipiscing elit" dolor 

array("Lorem", "ipsum", "dolor sit amet", "consectetur", "adipiscing elit", "dolor") 

所以,在報價單中的文本作爲被處理一個字。

下面是我對現在:

$mytext = "Lorem ipsum %22dolor sit amet%22 consectetur %22adipiscing elit%22 dolor" 
$noquotes = str_replace("%22", "", $mytext"); 
$newarray = explode(" ", $noquotes); 

,但我的代碼將每個字到一個數組。我如何在引號內將單詞作爲一個單詞處理?

+2

這聽起來像一個正則表達式的工作 – Earlz 2010-02-04 19:10:01

+0

另請參閱[爆炸()函數,忽略引號內的字符?](http://stackoverflow.com/questions/3264775/an-explode-function-that-ignores-characters -Iside-quotes) – Bergi 2013-09-10 21:43:50

回答

79

你可以使用一個preg_match_all(...)

$text = 'Lorem ipsum "dolor sit amet" consectetur "adipiscing \\"elit" dolor'; 
preg_match_all('/"(?:\\\\.|[^\\\\"])*"|\S+/', $text, $matches); 
print_r($matches); 

這將產生:

Array 
(
    [0] => Array 
     (
      [0] => Lorem 
      [1] => ipsum 
      [2] => "dolor sit amet" 
      [3] => consectetur 
      [4] => "adipiscing \"elit" 
      [5] => dolor 
     ) 

) 

正如你所看到的,這也說明了引號的字符串內轉義引號。

編輯

的簡短解釋:

"   # match the character '"' 
(?:   # start non-capture group 1 
    \\  # match the character '\' 
    .   # match any character except line breaks 
    |   # OR 
    [^\\"] # match any character except '\' and '"' 
)*   # end non-capture group 1 and repeat it zero or more times 
"   # match the character '"' 
|   # OR 
\S+   # match a non-whitespace character: [^\s] and repeat it one or more times 

而且在匹配%22,而不是雙引號的情況下,你會怎麼做:

preg_match_all('/%22(?:\\\\.|(?!%22).)*%22|\S+/', $text, $matches); 
+0

是否有理由不使用'preg_split'而不是'preg_match_all'?它看起來像一個更自然的國際海事組織。 – prodigitalson 2010-02-04 19:20:08

+0

太棒了!我將不得不研究一下代碼以確定發生的事情!感謝 – timofey 2010-02-04 19:21:10

+2

@prodigitalson:沒有,使用'使preg_split(...)'你無法解釋轉義字符。 'preg_match_all(...)'「表現得更像是一個解析器,這是更自然的事情。此外,在使用'使preg_split(...)',你需要提前看各的空間,看看有多少引號是在它前面,使它成爲一個'爲O(n^2)'操作:對於小沒問題字符串,但是當涉及更大的字符串時可能會減少運行時間。 – 2010-02-04 19:31:17

62

這將更加用str_getcsv()更容易。

$test = 'Lorem ipsum "dolor sit amet" consectetur "adipiscing elit" dolor'; 
var_dump(str_getcsv($test, ' ')); 

給你

array(6) { 
    [0]=> 
    string(5) "Lorem" 
    [1]=> 
    string(5) "ipsum" 
    [2]=> 
    string(14) "dolor sit amet" 
    [3]=> 
    string(11) "consectetur" 
    [4]=> 
    string(15) "adipiscing elit" 
    [5]=> 
    string(5) "dolor" 
} 
+0

這適用於我的開發機器,但不適用於我的生產服務器。 : -/ – 2012-03-17 18:22:26

+4

str_getcsv需要PHP 5.3。 – armakuni 2013-08-02 06:18:38

+3

啊爲什麼我現在才發現這個功能?! – 2015-01-03 07:38:09

4

您也可以嘗試這種多爆炸功能

function multiexplode ($delimiters,$string) 
{ 

$ready = str_replace($delimiters, $delimiters[0], $string); 
$launch = explode($delimiters[0], $ready); 
return $launch; 
} 

$text = "here is a sample: this text, and this will be exploded. this also | this one too :)"; 
$exploded = multiexplode(array(",",".","|",":"),$text); 

print_r($exploded); 
+2

這個答案很好,但是如果你要求它在空格和引號上拆分,它會在引號內的空格上分開。 – starbeamrainbowlabs 2015-05-20 16:38:54

1

在某些情況下鮮爲人知的token_get_all()可能證明是有用的:

$tokens = token_get_all("<?php $text ?>"); 
$separator = ' '; 
$items = array(); 
$item = ""; 
$last = count($tokens) - 1; 
foreach($tokens as $index => $token) { 
    if($index != 0 && $index != $last) { 
     if(count($token) == 3) { 
      if($token[0] == T_CONSTANT_ENCAPSED_STRING) { 
       $token = substr($token[1], 1, -1); 
      } else { 
       $token = $token[1]; 
      } 
     } 
     if($token == $separator) { 
      $items[] = $item; 
      $item = ""; 
     } else { 
      $item .= $token; 
     } 
    } 
} 

Resul TS:

Array 
(
    [0] => Lorem 
    [1] => ipsum 
    [2] => dolor sit amet 
    [3] => consectetur 
    [4] => adipiscing elit 
    [5] => dolor 
) 
1

我來到這裏有一個類似的複雜的字符串分割的問題,但沒有答案在這裏也正是我想要的 - 所以我寫了我自己。

我在這裏發佈它,以防萬一它對別人有幫助。

這可能是一種非常緩慢且低效的方式 - 但它適用於我。

function explode_adv($openers, $closers, $togglers, $delimiters, $str) 
{ 
    $chars = str_split($str); 
    $parts = []; 
    $nextpart = ""; 
    $toggle_states = array_fill_keys($togglers, false); // true = now inside, false = now outside 
    $depth = 0; 
    foreach($chars as $char) 
    { 
     if(in_array($char, $openers)) 
      $depth++; 
     elseif(in_array($char, $closers)) 
      $depth--; 
     elseif(in_array($char, $togglers)) 
     { 
      if($toggle_states[$char]) 
       $depth--; // we are inside a toggle block, leave it and decrease the depth 
      else 
       // we are outside a toggle block, enter it and increase the depth 
       $depth++; 

      // invert the toggle block state 
      $toggle_states[$char] = !$toggle_states[$char]; 
     } 
     else 
      $nextpart .= $char; 

     if($depth < 0) $depth = 0; 

     if(in_array($char, $delimiters) && 
      $depth == 0 && 
      !in_array($char, $closers)) 
     { 
      $parts[] = substr($nextpart, 0, -1); 
      $nextpart = ""; 
     } 
    } 
    if(strlen($nextpart) > 0) 
     $parts[] = $nextpart; 

    return $parts; 
} 

用法如下。explode_adv需要5個參數:

  1. 打開塊的字符數組 - 例如, [(
  2. 該關閉塊字符數組 - 例如],)
  3. 切換塊的字符數組 - 例如, ",'
  4. 應該導致拆分到下一部分的字符數組。
  5. 串去努力。

此方法可能存在缺陷 - 歡迎編輯。