2010-07-10 265 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

相关问题