【问题标题】:PHP: String to multidimensional arrayPHP:字符串到多维数组
【发布时间】:2017-07-08 00:18:36
【问题描述】:

(对不起,我的英语不好)

我有一个要拆分为数组的字符串。 角括号是多个嵌套数组。 应保留转义字符。

这是一个示例字符串:

$string = '[[["Hello, \"how\" are you?","Good!",,,123]],,"ok"]'

结果结构应如下所示:

array (
  0 => 
  array (
    0 => 
    array (
      0 => 'Hello, \"how\" are you?',
      1 => 'Good!',
      2 => '',
      3 => '',
      4 => '123',
    ),
  ),
  1 => '',
  2 => 'ok',
)

我已经测试过了:

$pattern = '/[^"\\]*(?:\\.[^"\\]*)*/s';
$return = preg_match_all($pattern, $string, null);

但这并不能正常工作。我不理解这些 RegEx 模式(我在本页的另一个示例中发现了这一点)。 我不知道 preg_match_all 是否是正确的命令。

我希望有人可以帮助我。

非常感谢!!!

【问题讨论】:

    标签: php arrays regex


    【解决方案1】:

    如果您可以编辑序列化数据的代码,那么最好使用 json_encode 和 json_decode 来处理序列化。无需重新发明轮子。

    顺便说一句,好猫。

    【讨论】:

      【解决方案2】:

      这对于正则表达式来说是一个棘手的问题 - 但您的问题有一个 hack 答案(提前道歉)。

      字符串几乎是一个有效的数组文字,但对于,,s。您可以匹配这些对,然后使用

      转换为 ,''s

      /,(?=,)/

      然后你可以eval将该字符串放入你要查找的输出数组中。

      例如:

      // input 
      $str1 = '[[["Hello, \\"how\\" are you?","Good!",,,123]],,"ok"]';
      
      // replace , followed by , with ,'' with a regex
      $pattern = '/,(?=,)/';
      $replace = ",''";
      $str2 = preg_replace($pattern, $replace, $str1);
      
      // eval updated string
      $arr = eval("return $str2;");
      var_dump($arr);
      

      我明白了:

      array(3) {
        [0]=>
        array(1) {
          [0]=>
          array(5) {
            [0]=>
            string(21) "Hello, "how" are you?"
            [1]=>
            string(5) "Good!"
            [2]=>
            string(0) ""
            [3]=>
            string(0) ""
            [4]=>
            int(123)
          }
        }
        [1]=>
        string(0) ""
        [2]=>
        string(2) "ok"
      }
      

      编辑

      注意到eval 的内在危险,更好的选择是使用json_decode 和上面的代码,例如:

      // input 
      $str1 = '[[["Hello, \\"how\\" are you?","Good!",,,123]],,"ok"]';
      
      // replace , followed by , with ,'' with a regex
      $pattern = '/,(?=,)/';
      $replace = ',""';
      $str2 = preg_replace($pattern, $replace, $str1);
      
      // eval updated string
      $arr = json_decode($str2);
      var_dump($arr);
      

      【讨论】:

      • 使用 eval 是一种危险的方式,因为您不知道字符串包含什么。将,(?=,) 替换为,'' 不会处理,, 在引号之间的情况。恐怕这样做的唯一方法是逐个字符地解析字符串或尝试将其转换为众所周知的格式,例如 JSON。但这不是一件容易的事,但也不是不可能。
      • 你是对的 - 我已经为问题中的黑客答案道歉。我相信json_encode 也存在与,, 问题相同的挑战。
      • 抱歉 - json_decode - 如果将 ,, 替换为 "" 例如var_dump(json_decode('[[["Hello, \"how\" are you?","Good!","","",123]],"","ok"]'));,这将起作用。例如var_dump(json_decode('[[["Hello, \"how\" are you?","Good!","","",123]],"","ok"]'));
      • 您可以使用$string = preg_replace('~"[^"\\\\]*+(?s:\\\\.[^"\\\\]*)*+"?(*SKIP)(*F)|,\K(?=[],])|\[\K(?=,)~', '""',$string); 解决,, 问题(也可以处理[,,] 等情况,并避免引用字符串。)
      【解决方案3】:

      您可能希望将词法分析器与实际构建结构的递归函数结合使用。

      出于您的目的,已使用以下令牌:

      \[           # opening bracket
      \]           # closing bracket
      ".+?(?<!\\)" # " to ", making sure it's not escaped
      ,(?!,)       # a comma, not followed by a comma
      \d+          # at least one digit
      ,(?=,)       # a comma followed by a comma
      

      剩下的就是编程逻辑,见demo on ideone.com。启发by this post


      class Lexer {
          protected static $_terminals = array(
              '~^(\[)~'               => "T_OPEN",
              '~^(\])~'               => "T_CLOSE",
              '~^(".+?(?<!\\\\)")~'   => "T_ITEM",
              '~^(,)(?!,)~'           => "T_SEPARATOR",
              '~^(\d+)~'              => "T_NUMBER",
              '~^(,)(?=,)~'           => "T_EMPTY"
          );
      
          public static function run($line) {
              $tokens = array();
              $offset = 0;
              while($offset < strlen($line)) {
                  $result = static::_match($line, $offset);
                  if($result === false) {
                      throw new Exception("Unable to parse line " . ($line+1) . ".");
                  }
                  $tokens[] = $result;
                  $offset += strlen($result['match']);
              }
              return static::_generate($tokens);
          }
      
          protected static function _match($line, $offset) {
              $string = substr($line, $offset);
      
              foreach(static::$_terminals as $pattern => $name) {
                  if(preg_match($pattern, $string, $matches)) {
                      return array(
                          'match' => $matches[1],
                          'token' => $name
                      );
                  }
              }
              return false;
          }
      
          // a recursive function to actually build the structure
          protected static function _generate($arr=array(), $idx=0) {
              $output = array();
              $current = 0;
              for($i=$idx;$i<count($arr);$i++) {
                  $type = $arr[$i]["token"];
                  $element = $arr[$i]["match"];
                  switch ($type) {
                      case 'T_OPEN':
                          list($out, $index) = static::_generate($arr, $i+1);
                          $output[] = $out;
                          $i = $index;
                          break;
                      case 'T_CLOSE':
                          return array($output, $i);
                          break;
                      case 'T_ITEM':
                      case 'T_NUMBER':
                          $output[] = $element;
                          break;
                      case 'T_EMPTY':
                          $output[] = "";
                          break;
                  }
              }
              return $output;
          }    
      }
      
      $input  = '[[["Hello, \"how\" are you?","Good!",,,123]],,"ok"]';
      $items = Lexer::run($input);
      print_r($items);
      
      ?>
      

      【讨论】:

      • @然后考虑投票/接受答案(左侧的绿色勾号)。
      猜你喜欢
      • 2014-07-16
      • 2019-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多