2010-07-10 263 views
0

我正在處理模板類,並試圖從字符串參數列表中解析出帶引號的字符串列表。舉個例子字符串:用於在字符串中匹配雙引號和/或單引號字符串的PHP正則表達式

$string = 'VAR_SELECTED, \'Hello m\'lady\', "null"'; 

我在未來與提取字符串「Hello m'lady」和「空」正則表達式的問題。我已經得到的最接近是

$string = 'VAR_SELECTED, \'Hello m\'lady\', "null", \'TE\'ST\''; 
preg_match_all('/(?:[^\']|\\\\.)+|(?:[^"]|\\\\.)+/', $string, $matches); 
print_r($matches); 

,輸出:

Array 
(
    [0] => Array 
     (
      [0] => VAR_SELECTED, 
      [1] => 'Hello m'lady', 
      [2] => "null", 
      [3] => 'TE'ST' 
     ) 

) 

但是更復雜的情況:

$string = 'VAR_SELECTED, \'Hello "Father"\', "Hello \'Luke\'"'; 
preg_match_all('/(?:[^\']|\\\\.)+|(?:[^"]|\\\\.)+/', $string, $matches); 
print_r($matches); 

輸出:

Array 
(
    [0] => Array 
     (
      [0] => VAR_SELECTED, 
      [1] => 'Hello 
      [2] => "Father" 
      [3] => ', 
      [4] => "Hello 
      [5] => 'Luke' 
      [6] => " 
     ) 

) 

誰能幫助我解決這個問題?多個正則表達式是前進的方向嗎?

編輯也許用一個佔位符替換字符串中的逗號,然後用爆炸拆分字符串會更容易?

編輯2只是想到了一個簡單的不安全選項(我不打算使用),但會生成一個E_NOTICE錯誤。

$string = 'return array(VAR_SELECTED, \'Hello , "Father"\', "Hello \'Luke\'4");'; 
$string = eval($string); 
print_r($string); 
+0

您如何知道在上面給出的示例中的「m'lady」中的撇號包含在引號內 - 如果字符串中有更多的單引號,這會不會破裂? – 2010-07-10 17:09:19

+0

這是有點我想解決的問題。 – buggedcom 2010-07-10 18:23:36

回答

3

試試這個:

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

,或作爲PHP單引號字符串字面量:

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

該正則表達式得到想要的結果,但我認爲你會犯這個錯誤。通常,如果引用的字符串需要包含文字引號字符,則引號將被轉義,或者帶有反斜槓或另一個引號。你沒有這樣做,所以我不得不使用基於lookarounds的脆弱黑客。你確定數據不應該看起來像這樣嗎?

$string = 'VAR_SELECTED, \'Hello m\\'lady\', "null"'; 

$string = 'VAR_SELECTED, \'Hello "Father"\', "Hello \\'Luke\\'"'; 

想想吧,PHP不內置支持CSV數據嗎?

+0

問題是他說逗號可以在字符串本身,以及未轉義的引號和混合我幾乎認爲他需要抓取字符串才能找到無與倫比的「開始」字符,但這是非常糟糕的C++ ish for php。 – Caladain 2010-07-10 18:54:38

+0

謝謝,但我認爲你的正則表達式有它,PHP確實有一個CSV解析器和一個str函數(php> = 5.3),但是在這個問題中,php仍然無法正確解析數據,因爲外殼可以是同一個參數列表中的「或者」,我知道愚蠢,但模板設計師很愚蠢。 @Caladain - 我認爲這實際上解決了它。用preg_match試試這個字符串。 $ string ='VAR_SELECTED,\'Hello,「Father」\',「Hell,o \'Luke \'」,\',「\''; – buggedcom 2010-07-10 19:03:48

+0

請考慮以下字符串:$ string ='VAR_SELECTED,'Hello, \'「Fa \'ther'\」,「您好,\」盧克,「我的兒子」\'「'; 不會打破正確的,Alan的發起在這裏我認爲是正確的,Lookarounds和backtracking可以很脆弱。統一格式化和轉義數據使得這個問題變得簡單得多,否則你永遠不能保證你不會餵養一個格式不正確的字符串(有時候是爲了注入代碼,有時候是因爲用戶是猴子敲擊鍵盤而不在意關於正確轉義的東西) – Caladain 2010-07-10 19:22:30

0

您想在匹配字符串中使用back reference

preg_match_all('@([\'"]).*[^\\\\]\[email protected]', $string, $matches); 

這將開始的第一個實例匹配「或「再匹配以匹配結束最長的字符串」或」該逃脫。

Array (
[0] => Array 
    (
     [0] => 'Hello m'lady', "null", 'TE'ST' 
    ) 

[1] => Array 
    (
     [0] => ' 
    ) 
+0

嗯,所需的匹配雖然是'你好m'lady','null'和'TE'ST'作爲單獨的字符串,而不是一個長的字符串。 – buggedcom 2010-07-10 17:53:06

+0

哦,好的。我誤解了問題所在。這就是老啤酒的一個障礙。 – 2010-07-11 13:40:42

1

下面是我會做:

下把任務分成要採取分步驟:

1)發生爆炸逗號的字符串。

For 'VAR_SELECTED, \'Hello m\'lady\', "null"' this gives me 
[0]=>"VAR_SELECTED" 
[1]=>" \'Hello m\'lady\'" 
[2]=>" "null"" 

For 'VAR_SELECTED, \'Hello "Father"\', "Hello \'Luke\'"' this gives me 
[0]=>"VAR_SELECTED" 
[1]=>" \'Hello "Father"\'" 
[2]=>" "Hello \'Luke\'"" 

2)運行修剪在所有三個擺脫任何空白的

For 'VAR_SELECTED, \'Hello m\'lady\', "null"' this gives me 
[0]=>"VAR_SELECTED" 
[1]=>"\'Hello m\'lady\'" 
[2]=>""null"" 

For 'VAR_SELECTED, \'Hello "Father"\', "Hello \'Luke\'"' this gives me 
[0]=>"VAR_SELECTED" 
[1]=>"\'Hello "Father"\'" 
[2]=>""Hello \'Luke\'"" 

3)運行str_replace函數( 「\」,」」,$文本)擺脫斜線。 (只刪除spaces..added的可讀性,所以這應該是一個赤裸裸的斜線和「空」字符串)

For 'VAR_SELECTED, \'Hello m\'lady\', "null"' this gives me 
[0]=>"VAR_SELECTED" 
[1]=>"'Hello m'lady'" 
[2]=>""null"" 

For 'VAR_SELECTED, \'Hello "Father"\', "Hello \'Luke\'"' this gives me 
[0]=>"VAR_SELECTED" 
[1]=>"'Hello "Father"'" 
[2]=>""Hello 'Luke'"" 

4)再次運行修剪,修剪只($文字,「'」「)(移除spaces..added僅出於可讀性)

For 'VAR_SELECTED, \'Hello m\'lady\', "null"' this gives me 
[0]=>"VAR_SELECTED" 
[1]=>"Hello m'lady" 
[2]=>"null" 

For 'VAR_SELECTED, \'Hello "Father"\', "Hello \'Luke\'"' this gives me 
[0]=>"VAR_SELECTED" 
[1]=>"Hello "Father"" 
[2]=>"Hello 'Luke'" 

我沒有測試過這一點,但邏輯是健全的。一個快速和骯髒的方式來測試所有的98%的正則表達式的(在我的經驗)是使用http://rubular.com/這是一個很棒的網站。通常如果它開始在正則表達式中窒息,這是我的第一個信號,我應該更多地解決這個問題。 (這只是輿論〜穿上防火服〜)

+0

如果這些字符串不包含逗號本身,那麼這將起作用,否則您也會破壞字符串。 – buggedcom 2010-07-10 17:45:29

+0

其實,你需要能夠有一個模式或字符串來描述字符串中的每個「字段」。逗號,&,!..的東西。否則沒有辦法將工作..電腦太愚蠢。如果你在字符串中間放置了字符或圖案,正則表達式或其他方法將會在該圖案上「分割」。 – Caladain 2010-07-10 18:25:43

+0

確實引號是這樣做的嗎?你的意思是一個不尋常的字符串像#或什麼的 – buggedcom 2010-07-10 18:27:29

相關問題