2013-04-23 83 views
-2

如何(最簡單的方式)像匹配的密鑰在PHP字符串=「值」的格局

oneKey="value 1" key2="value 2" anotherKey="value 3" somekey="value containing spaces" 

字符串轉換成數組與PHP(正則表達式或沒有)?

我想中檢索這樣的價值觀:

$myArray['key'] 

所以

$myArray['oneKey'] == "value" 

的所有按鍵均不同

+0

請顯示您已經嘗試過的代碼,以便我們可以提供對您的情況有所幫助的特定響應。 – 2013-04-23 15:27:38

+4

我希望你不是想解析HTML屬性... – 2013-04-23 15:28:01

+0

所有的鍵都一樣嗎?是'關鍵'這裏使用的關鍵字? – 2013-04-23 15:28:21

回答

4

匹配引號中的字符串始終是棘手。

假設你的數據決不會包含一個轉義雙引號(即雙引號是實際值的一部分,一個簡單的

/(?<=^|\s)([^=]+)="([^"]*)"/ 

...可能會做的工作,但它不太可能會。情況所以我們需要比這稍微複雜一些,而這也正是弗裏德爾的經典作品「展開循環」就派上用場了:

/(?<=^|\s)([^=\s]+)="((?:[^\\"]|\\.)*)"/ 

如何運作好了,讓我們來分析一下:

首先,我們先從回顧後,以驗證匹配的開始點由串的開始或空白字符之前:

(?<=^|\s) 

接下來我們尋找非空白和非的任何組合等號(至少1個)。這是關鍵,所以我們把它放在一個捕獲組:

([^=\s]+) 

接下來我們有一個文字等號與雙引號:

=" 

下它的「展開循環」。這可能有點難以理解,但它通過查找任何不是引號字符或轉義字符(我選擇反斜槓作爲轉義字符但真的可以使用任何內容)的任何字符,轉義字符後跟其他任何字符。這是重複零次或多次。由於這是價值,我們把它包在捕獲組:

((?:[^\\"]|\\.)*) 

然後我們只需關閉與字面雙引號:

" 

把它全部PHP代碼和你喜歡的東西這樣的:

$subject = 'key1="value 1" key2="value 2" key3="value 3" key4="value containing spaces"'; 

$expr = '/(?<=^|\\s)([^=\\s]+)="((?:[^\\\\"]|\\\\.)*)"/'; 
preg_match_all($expr, $subject, $matches); 

$result = array(); 
foreach ($matches[1] as $i => $key) { 
    $result[$key] = $matches[2][$i]; 
} 

See it working


但是這有一個小問題。考慮what happens當目標字符串是:

key1="value\" 1" 

應該是不錯的,簡單的,這只是一個轉義報價,對不對?那麼,這是真的,上述表達式可以輕鬆處理這種情況。但看看輸出:

Array 
(
    [key1] => value\" 1 
) 

轉義字符仍然在結果字符串中作爲文字。這不是我們想要的。但是上面的表達式只會從主題字符串中提取相關的組件,它根本不會對它們進行調整。爲此,我們需要一個單獨的過程 - 但現在只是一個簡單的搜索和替換,因爲我們已經將字符串分解成我們想要的標記。

所以我們只是做這樣的事情:

$result = preg_replace_callback('/\\\\./', function($match) { 
    switch ($match[0][1]) { // inspect the second character 
     // here we can define our special escape sequences, for example: 
     case 'r': return "\r"; 
     case 'n': return "\n"; 

     // For anything that we don't handle as a special case, we just return 
     // the second character in the match, effectively strip the escape 
     default: return $match[0][1]; 
    } 
}, $subject); 

所以,當你把上述代碼放在一起,你會得到一個更多的東西是這樣的:

$subject = 'key1="value \" 1" key2="value \n 2" key3="value 3" key4="value containing spaces"'; 

$matchExpr = '/(?<=^|\\s)([^=\\s]+)="((?:[^\\\\"]|\\\\.)*)"/'; 
$replaceExpr = '/\\\\./'; 

$replaceCallback = function($match) { 
    switch ($match[0][1]) { 
     case 'r': return "\r"; 
     case 'n': return "\n"; 
     default: return $match[0][1]; 
    } 
}; 

preg_match_all($matchExpr, $subject, $matches); 

$result = array(); 
foreach ($matches[1] as $i => $key) { 
    $result[$key] = preg_replace_callback($replaceExpr, $replaceCallback, $matches[2][$i]); 
} 

See it working

+0

哇!這是一個很好的答案。非常有用,謝謝! – W3Max 2013-04-23 15:57:36

0

嘗試這個表達式與preg_match_all

/(key[0-9]{0,})\="(.+?)"/ims 

,回到比賽將有鍵和值

+2

'key11','key100' – Anirudha 2013-04-23 15:32:53

+0

怎麼樣現在... – 2013-04-23 15:35:02

+0

'鍵[0-9] +'或'鍵\ d +'會更好 – Anirudha 2013-04-23 15:35:57

-2
$func = function($string) { $kv = preg_split(/="/, $string); $kv[1] = substr($kv[1], 0, length($kv[1]-1])); $myArray[$kv[0]] = $kv[1]; }; 
array_map($func, preg_split(/[[:space:]]+/, $string));