PHP - 如何使用逗号分解字符串,当逗号位于撇号内时,除了位置


PHP - how to explode a string using a comma, except situtation when this comma is inside apostrophes?

我有以下文字:

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

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

所以我这样做:

$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() 函数爆炸后,它显然不像我想要的那样工作。

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

使用以下命令进行拆分:

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

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

法典:

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

你要找的是标记化。不要试图在逗号上拆分。相反,请标识表达式的每个构建基块。所以你需要匹配,而不是分裂

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

'[^']+'

将匹配以下元素:

@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']])
          '___________/  '________________/ '______________________________________________________/

演示

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

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

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

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

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

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

尝试使用这个:

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

这将匹配

@include (''file_to_load'')

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

我希望这有所帮助。