【问题标题】:How can I break a string up by spaces in PHP, respecting quoted sub strings?如何在 PHP 中用空格分解字符串,尊重带引号的子字符串?
【发布时间】:2011-12-26 06:28:40
【问题描述】:

如何在 PHP 中使用空格来拆分字符串,同时尊重带引号的子字符串?我认为必须有一些命令来解析这种类型的字符串,如参数,但我不知道那是什么。

示例字符串:

$string = '12345 abcd "hello world" defgh "nice to meet you" 34554';

我通常使用这三种中的一种来分解字符串。但我不认为他们有能力像我建议的那样拆线。

$result = str_replace(' ',"\n",$string);
$result = explode(' ',$string);
$result = preg_replace('#\s#',"\n",$string);

结果:

12345
abcd
"hello
world"
defgh
"nice
to
meet
you"
34554

期望的结果:

12345
abcd
hello world
defgh
nice to meet you
34554

更新

我想我对 PHP 处理 URL 查询变量的 parse_str 命令印象深刻,并希望 PHP 有一些我可以在这个例子中工作的东西,有点像 getopt 对命令行参数所做的那样。

【问题讨论】:

    标签: php regex string parsing arguments


    【解决方案1】:

    这应该可以正常工作:

    function spaceExplode($var)
    {
        $chunks = explode('"', $var);
        array_walk($chunks, function(&$text) {
            $text = trim($text);
        });
    
        $subchunks = array();
        foreach ($chunks as $key => $value) {
            if ($key % 2 != 0) {
                $subchunks[] = $value;
            } else {
                $subchunks = array_merge($subchunks, explode(' ', $value));
            }
        }
    
        return $subchunks;
    }
    

    另一种方法是在编辑之前使用strtok@Romain 在他的回答中建议:)):

    function tokenize($var, $char)
    {
        $tokens = array(strtok($var, $char));
    
        do {
            $tokens[] = strtok($char);
        } while(end($tokens) !== false);
    
        foreach ($tokens as $key => $token) {
            $tokens[$key] = trim($token);
    
            if (empty($tokens[$key])) {
                unset($tokens[$key]);
            }
        }
    
        return $tokens;
    }
    

    【讨论】:

    • 基本上这就是实现我所建议的工作方式的代码(因此我赞成它:D)。
    • 是的,我刚刚阅读了您的回答。不知道strtok。我认为应该使用该解决方案。
    【解决方案2】:

    给你:

    $s = '12345 abcd "hello world" defgh "nice to meet you" 34554';
    $m = preg_split('/"([^"]*)"|([^\s]+)/', $s, -1, PREG_SPLIT_DELIM_CAPTURE);
    $m = array_values(array_filter(array_map('trim', $m)));
    var_export($m);
    

    输出是:

    array (
      0 => '12345',
      1 => 'abcd',
      2 => 'hello world',
      3 => 'defgh',
      4 => 'nice to meet you',
      5 => '34554',
    )
    

    【讨论】:

      【解决方案3】:

      您可以为此使用fgetcsv() / str_getcsv()

      <?php
      $string = '12345 abcd "hello world" defgh "nice to meet you" 34554';
      $row = str_getcsv($string, ' ');
      var_dump($row);
      

      打印

      array(6) {
        [0]=>
        string(5) "12345"
        [1]=>
        string(4) "abcd"
        [2]=>
        string(11) "hello world"
        [3]=>
        string(5) "defgh"
        [4]=>
        string(16) "nice to meet you"
        [5]=>
        string(5) "34554"
      }
      

      【讨论】:

        【解决方案4】:

        您的操作顺序错误:首先在引号上展开(这样您就可以轻松隔离带引号的子字符串),然后根据空格展开。

        我会将实际代码作为练习提供给您,但本质上是:

        12345 abcd "hello world" defgh "nice to meet you" 34554
        

        变成

        12345 abcd
        hello world
        defgh
        nice to meet you
        34554
        

        然后你会使用空格分开,但只使用不在引号之间的行(即所有具有偶数索引的行,假设第一个单元格的索引为 0,即偶数):

        12345 abcd           -> Split
        hello world          -> Don't split
        defgh                -> Split
        nice to meet you     -> Don't split
        34554                -> Split
        

        所以它变成了:

        12345
        abcd
        hello world
        defgh
        nice to meet you
        34554
        

        显然,如果您可以使用“转义引号”,则需要以某种方式考虑这些 - 也可以作为练习留给读者(这很容易,真的)。

        【讨论】:

        • 谢谢。这些命令不应该是顺序的 - 只是显示我通常解析字符串的方式,只是为了详细说明这个问题。
        • @cwd 我知道 - 只是给你一些可以解决问题的逻辑(不是 PHP 专家,因此我没有尝试在那里抛出一些代码)。但是,有不止一种方法可以做到这一点,而且有些方法可能比其他方法表现更好(绝对不是说我的方法是最好的)。
        • 谢谢。我确实在问题的底部又做了一个。
        猜你喜欢
        • 2010-09-09
        • 2023-01-13
        • 1970-01-01
        • 2018-04-07
        • 1970-01-01
        • 2018-01-11
        • 2011-04-16
        相关资源
        最近更新 更多