用于匹配字符串中的双引号和/或单引号字符串的PHP正则表达式

时间:2010-07-10 16:55:44

标签: php regex string preg-match-all

我正在处理模板类,在尝试从字符串参数列表中解析出引用字符串列表时遇到问题。以字符串为例:

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

我遇到了一个提取字符串“Hello m'lady”和“null”的正则表达式的问题。我最接近的是

$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);

3 个答案:

答案 0 :(得分:3)

试试这个:

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

或者,作为PHP单引号字符串文字:

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

正则表达式产生了预期的结果,但我认为你会出现这种错误。通常,如果带引号的字符串需要包含文字引号字符,则使用反斜杠或其他引号对引号进行转义。你没有这样做,所以我不得不使用基于外观的脆弱黑客。你确定数据不应该是这样的吗?

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

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

想一想,PHP是否内置了对CSV数据的支持?

答案 1 :(得分: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(“\”,“”,$ text)去掉斜杠。 (删除space..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.。)再次运行修剪,仅修剪($ text,“'”“)(删除空格......仅为了可读性而添加)

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/这是一个很棒的网站。通常,如果它开始扼杀正则表达式,这是我的第一个迹象,我应该更多地解决问题。 (这只是意见〜防火服〜)

答案 2 :(得分:0)

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

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

这将开始与“or”的第一个实例匹配,然后匹配以匹配的最长字符串“或”转义。

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

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