2012-09-10 115 views
3

我試圖使用PHP將字符串拆分爲數組組件,使用"'作爲分隔符。我只想分割最外面的字符串。這裏有四個例子,每個所期望的結果:字符串到陣列,由單引號和雙引號拆分

$pattern = "?????"; 
$str = "the cat 'sat on' the mat"; 
$res = preg_split($pattern, $str); 
print_r($res); 
/*output: 
Array 
(
    [0] => the cat 
    [1] => 'sat on' 
    [2] => the mat 
)*/ 

$str = "the cat \"sat on\" the mat"; 
$res = preg_split($pattern, $str); 
print_r($res); 
/*output: 
Array 
(
    [0] => the cat 
    [1] => "sat on" 
    [2] => the mat 
)*/ 

$str = "the \"cat 'sat' on\" the mat"; 
$res = preg_split($pattern, $str); 
print_r($res); 
/*output: 
Array 
(
    [0] => the 
    [1] => "cat 'sat' on" 
    [2] => the mat 
)*/ 

$str = "the 'cat \"sat\" on' the mat 'when \"it\" was' seventeen"; 
$res = preg_split($pattern, $str); 
print_r($res); 
/*output: 
Array 
(
    [0] => the 
    [1] => 'cat "sat" on' 
    [2] => the mat 
    [3] => 'when "it" was' 
    [4] => seventeen 
)*/ 

,你可以看到我只想用最報價分裂,我想忽略報價內的任何報價。

最接近我已經拿出了$pattern

$pattern = "/((?P<quot>['\"])[^(?P=quot)]*?(?P=quot))/"; 

,但顯然這是行不通的。

回答

2

您可以使用preg_splitPREG_SPLIT_DELIM_CAPTURE選項。正則表達式不如@JanTuroň的反向引用方法那樣優雅,因爲所需的捕獲組混淆了結果。

$str = "the 'cat \"sat\" on' the mat the \"cat 'sat' on\" the mat"; 
$match = preg_split("/('[^']*'|\"[^\"]*\")/U", $str, null, PREG_SPLIT_DELIM_CAPTURE); 
print_r($match); 
+1

我相信你的解決方案更加優雅。 +1 –

+0

那就是我以前的樣子。它的驚人之處在於它不需要反向引用,但非常棒! – mulllhausen

+0

如果我想擴展正則表達式來忽略轉義引號會很容易嗎? 「在上的 '中Cat S \' 例如'$ STR =」在墊子」'應該給'[0] =>的,[1] => '中Cat S \' 在上「,[2] =>此mat'。如果沒有,那麼我會爲此添加一個新的新問題。乾杯! – mulllhausen

0

您可以使用back referencesungreedy modifierpreg_match_all

$str = "the 'cat \"sat\" on' the mat 'when \"it\" was' seventeen"; 
preg_match_all("/(['\"])(.*)\\1/U", $str, $match); 
print_r($match[0]); 

現在,你有你的最外面的引號部分

[0] => 'cat "sat" on' 
[1] => 'when "it" was' 

你還可以用substrstrpos(一種黑盒查找字符串的其餘部分溶液)

$a = $b = 0; $result = array(); 
foreach($match[0] as $part) { 
    $b = strpos($str,$part); 
    $result[] = substr($str,$a,$b-$a); 
    $result[] = $part; 
    $a = $b+strlen($part); 
} 
$result[] = substr($str,$a); 
print_r($result); 

下面是結果

[0] => the 
[1] => 'cat "sat" on' 
[2] => the mat 
[3] => 'when "it" was' 
[4] => seventeen 

就脫光最終空標題/後緣元件如果報價在字符串的開始/結束。

+0

,做的工作,但它不匹配外返回位,這確實需要 – mulllhausen

+0

它是一個可能的解決方案。如果沒有人提出一個正則表達式的方法,那麼我將授予答案。但我更喜歡單個正則表達式,因爲它會更簡單。 – mulllhausen

+0

這不適用於最後一個例子? – JvdBerg

1

只需使用preg_match此:

$str = "the \"cat 'sat' on\" the mat"; 
$pattern = '/^([^\'"]*)(([\'"]).*\3)(.*)$/'; 

if (preg_match($pattern, $str, $matches)) { 
    printf("[initial] => %s\n[quoted] => %s\n[end] => %s\n", 
    $matches[1], 
    $matches[2], 
    $matches[4] 
); 
} 

此打印:

[initial] => the 
[quoted] => "cat 'sat' on" 
[end] => the mat 

這裏是正則表達式的解釋:

  • /^([^\'"]*) =>放最初的位直到fi在第一個被捕獲組中的第一個報價(單或雙)
  • (([\'"]).*\3) =>在\ 2中捕獲與最初報價相對應的文本(單或雙)(在\ 3中捕獲)必須與開場報價類型相同,因此\ 3)。事實上,正則表達式本質上是貪婪的,這有助於從第一個引號到最後一個引號,而不管裏面有多少引號。
  • (.*)$/ =>捕獲直到結束在\ 4
1

又一解決方案使用preg_replace_callback

$result1 = array(); 
function parser($p) { 
    global $result1; 
    $result1[] = $p[0]; 
    return "|"; // temporary delimiter 
} 

$str = "the 'cat \"sat\" on' the mat 'when \"it\" was' seventeen"; 
$str = preg_replace_callback("/(['\"]).*\\1/U", "parser", $str); 
$result2 = explode("|",$str); // using temporary delimiter 

現在可以使用array_map

$result = array(); 
function zipper($a,$b) { 
    global $result; 
    if($a) $result[] = $a; 
    if($b) $result[] = $b; 
} 
array_map("zipper",$result2,$result1); 
print_r($result); 

拉鍊那些陣列,其結果是

[0] => the 
[1] => 'cat "sat" on' 
[2] => the mat 
[3] => 'when "it" was' 
[4] => seventeen 

注:我會可能更好地創建一個類,這樣的壯舉,從而避免了全局變量。

相關問題