PHP - 如何使用逗号分解字符串,除了当这个逗号在撇号内时的位置?

时间:2015-06-13 17:39:44

标签: php regex

我有以下文字:

$string='
            blah<br>
            @include (\'file_to_load\')
            <br>
            @include (\'file_to_load\',\'param1\',\'param2\',\'param3\')
    ';

我想用参数(例如@include('file_to_load','param1','param2','param3'))来捕获(然后使用preg_replace_callback替换)所有出现的“@include”)

所以我这样做:

$string='
 blah<br>
 @include (\'file_to_load\')
 <br>
 @include (\'file_to_load\',\'param1\',\'param2\')
';
$params=[];
$result = preg_replace_callback(
    '~@include \((,?.*?)\)~',//I catch @include, parenthesis and all between them
    function ($matches) {
        echo '---iteration---';
        $params=explode(',',$matches[1]);//exploding by a comma
        echo '<pre>';
        var_dump($params);
        echo '</pre>';
        return $matches[1];
    },
    $string
);

一切都很好,直到逗号出现在里面一个参数,就像这里一样:

$string='
    blah<br>
    @include (\'file_to_load\')
    <br>
    @include (\'file_to_load\',\'param1,something\',[\'elem\'=>\'also, a comma\']])
';

这里我们在“param1”参数中有一个逗号,现在,在使用explode()函数爆炸后,它显然不能像我想的那样工作。

我有一种方法可以使用逗号来爆炸()(通过使用正则表达式)字符串,但是当逗号位于撇号内时不能吗?

3 个答案:

答案 0 :(得分:2)

使用以下内容进行拆分:

,(?=([^']*'[^']*')*[^']*$)

使用preg_split,因为explode不支持正则表达式:

<强>代码:

$params = preg_split(',(?=([^']*'[^']*')*[^']*$)',$matches[1]);

答案 1 :(得分:2)

您正在寻找的是标记化。不要试图分裂逗号。而是识别表达式的每个构建块。所以你需要匹配,而不是拆分

例如,这个简单的正则表达式:

'[^']+'

将匹配这些元素:

@include ('file_to_load','param1,something',['elem'=>'also, a comma'])
          \____________/ \________________/  \____/  \_____________/

但是对于你的情况可能还不够,因为你有一个数组,我想你也必须解析它。

分别识别每个参数:

'[^']+'|\[.+?\]
@include ('file_to_load','param1,something',['elem'=>'also, a comma'])
          \____________/ \________________/ \_______________________/

这种方法的问题在于它不允许您匹配嵌套数组。如果您需要能够解析它,那么模式会变得更复杂:

(?(DEFINE)
  (?<string>'[^']+')
  (?<array> \[ (?: (?&arrayitem) (?> , \s* (?&arrayitem) )* )? \] )
  (?<arrayitem> \s* (?&string) \s* => \s* (?&value) \s* )
  (?<value> (?&string) | (?&array) )
)
(?&value)

是的,这是一个递归的正则表达式,但它实际上可以识别参数:

@include ('file_to_load','param1,something',['elem'=>'also, a comma','other'=>['nested' => 'array']])
          \___________/  \________________/ \______________________________________________________/

Demo

由于我不知道您之后要对参数做什么,实际上您可能需要编写解析器而不是使用正则表达式,但这取决于您将要做什么分割参数后尝试做。

旁注:如果您希望能够在字符串中转义引号,则可能需要将'[^']+'字符串模式替换为更复杂的内容。

有两种广泛接受的方法可以做到这一点:

  • 使用反斜杠:'abc\'def'

    '(?:[^\\']++|\\.)*'
    
  • 报价加倍:'abc''def'

    '(?:[^']++|'')*'
    

答案 2 :(得分:0)

尝试使用:

"\@include[\s]*\([^\)]*\)"

这将匹配

@include (\'file_to_load\')

@include (\'file_to_load\',\'param1,something\',[\'elem\'=>\'also, a comma\']])

我希望这会有所帮助。