代码之家  ›  专栏  ›  技术社区  ›  hookedonwinter

使用PHP的JSON解析无效

  •  3
  • hookedonwinter  · 技术社区  · 15 年前

    我正在提取一个JSON提要,它是无效的JSON。完全没有引用。我试过一些方法,比如 explode() str_replace()

    下面是一个例子:

    id:43015,name:'John Doe',level:15,systems:[{t:6,glr:1242,n:'server',s:185,c:9}],classs:0,subclass:5
    

    编辑:我正在尝试使用 json_decode() 在这根绳子上。它什么也不返回。

    6 回复  |  直到 15 年前
        1
  •  11
  •   Marko    15 年前
    1. 所有的引号都应该是双引号 " 而不是单引号 '
    2. 所有的键都应该被引用。
    3. 整个元素应该是一个对象。
        function my_json_decode($s) {
            $s = str_replace(
                array('"',  "'"),
                array('\"', '"'),
                $s
            );
            $s = preg_replace('/(\w+):/i', '"\1":', $s);
            return json_decode(sprintf('{%s}', $s));
        }
    
        2
  •  5
  •   Marcos Fernandez Ramos    12 年前

    根据我的经验,马尔科的回答不再有效了。对于较新的php版本,请使用此istead:

    $a = "{id:43015,name:'John Doe',level:15,systems:[{t:6,glr:1242,n:'server',s:185,c:988}],classs:0,subclass:5}";
    $a = preg_replace('/(,|\{)[ \t\n]*(\w+)[ ]*:[ ]*/','$1"$2":',$a);
    $a = preg_replace('/":\'?([^\[\]\{\}]*?)\'?[ \n\t]*(,"|\}$|\]$|\}\]|\]\}|\}|\])/','":"$1"$2',$a);
    print_r($a);
    
        3
  •  4
  •   Guy    10 年前

    这个正则表达式就可以了

    $json = preg_replace('/([{,])(\s*)([A-Za-z0-9_\-]+?)\s*:/','$1"$3":',$json);
    
        4
  •  2
  •   Codesmith    8 年前

    我知道这个问题由来已久,但我希望这能帮助别人。

    最简单的方法似乎是编写自定义解析器。

    我想到了这个,它解析为嵌套的关联/索引数组:

    function loose_json_decode($json) {
        $rgxjson = '%((?:\{[^\{\}\[\]]*\})|(?:\[[^\{\}\[\]]*\]))%';
        $rgxstr = '%("(?:[^"\\\\]*|\\\\\\\\|\\\\"|\\\\)*"|\'(?:[^\'\\\\]*|\\\\\\\\|\\\\\'|\\\\)*\')%';
        $rgxnum = '%^\s*([+-]?(\d+(\.\d*)?|\d*\.\d+)(e[+-]?\d+)?|0x[0-9a-f]+)\s*$%i';
        $rgxchr1 = '%^'.chr(1).'\\d+'.chr(1).'$%';
        $rgxchr2 = '%^'.chr(2).'\\d+'.chr(2).'$%';
        $chrs = array(chr(2),chr(1));
        $escs = array(chr(2).chr(2),chr(2).chr(1));
        $nodes = array();
        $strings = array();
    
        # escape use of chr(1)
        $json = str_replace($chrs,$escs,$json);
    
        # parse out existing strings
        $pieces = preg_split($rgxstr,$json,-1,PREG_SPLIT_DELIM_CAPTURE);
        for($i=1;$i<count($pieces);$i+=2) {
            $strings []= str_replace($escs,$chrs,str_replace(array('\\\\','\\\'','\\"'),array('\\','\'','"'),substr($pieces[$i],1,-1)));
            $pieces[$i] = chr(2) . (count($strings)-1) . chr(2);
        }
        $json = implode($pieces);
    
        # parse json
        while(1) {
            $pieces = preg_split($rgxjson,$json,-1,PREG_SPLIT_DELIM_CAPTURE);
            for($i=1;$i<count($pieces);$i+=2) {
                $nodes []= $pieces[$i];
                $pieces[$i] = chr(1) . (count($nodes)-1) . chr(1);
            }
            $json = implode($pieces);
            if(!preg_match($rgxjson,$json)) break;
        }
    
        # build associative array
        for($i=0,$l=count($nodes);$i<$l;$i++) {
            $obj = explode(',',substr($nodes[$i],1,-1));
            $arr = $nodes[$i][0] == '[';
    
            if($arr) {
                for($j=0;$j<count($obj);$j++) {
                    if(preg_match($rgxchr1,$obj[$j])) $obj[$j] = $nodes[+substr($obj[$j],1,-1)];
                    else if(preg_match($rgxchr2,$obj[$j])) $obj[$j] = $strings[+substr($obj[$j],1,-1)];
                    else if(preg_match($rgxnum,$obj[$j])) $obj[$j] = +trim($obj[$j]);
                    else $obj[$j] = trim(str_replace($escs,$chrs,$obj[$j]));
                }
                $nodes[$i] = $obj;
            } else {
                $data = array();
                for($j=0;$j<count($obj);$j++) {
                    $kv = explode(':',$obj[$j],2);
                    if(preg_match($rgxchr1,$kv[0])) $kv[0] = $nodes[+substr($kv[0],1,-1)];
                    else if(preg_match($rgxchr2,$kv[0])) $kv[0] = $strings[+substr($kv[0],1,-1)];
                    else if(preg_match($rgxnum,$kv[0])) $kv[0] = +trim($kv[0]);
                    else $kv[0] = trim(str_replace($escs,$chrs,$kv[0]));
                    if(preg_match($rgxchr1,$kv[1])) $kv[1] = $nodes[+substr($kv[1],1,-1)];
                    else if(preg_match($rgxchr2,$kv[1])) $kv[1] = $strings[+substr($kv[1],1,-1)];
                    else if(preg_match($rgxnum,$kv[1])) $kv[1] = +trim($kv[1]);
                    else $kv[1] = trim(str_replace($escs,$chrs,$kv[1]));
                    $data[$kv[0]] = $kv[1];
                }
                $nodes[$i] = $data;
            }
        }
    
        return $nodes[count($nodes)-1];
    }
    

    请注意,确实如此

    对于您的情况,您似乎希望添加 {} 它的周围(如图所示) json_decode 还需要:

    $data = loose_json_decode('{' . $json . '}');
    

    这对我来说意味着:

    array(6) {
      ["id"]=>
      int(43015)
      ["name"]=>
      string(8) "John Doe"
      ["level"]=>
      int(15)
      ["systems"]=>
      array(1) {
        [0]=>
        array(5) {
          ["t"]=>
          int(6)
          ["glr"]=>
          int(1242)
          ["n"]=>
          string(6) "server"
          ["s"]=>
          int(185)
          ["c"]=>
          int(9)
        }
      }
      ["classs"]=>
      int(0)
      ["subclass"]=>
      int(5)
    }
    
        5
  •  1
  •   Vadim Cool    9 年前
    $json = preg_replace('/([{,])(\s*)([A-Za-z0-9_\-]+?)\s*:/','$1"$3":',$json);// adding->(")
    $json = str_replace("'",'"', $json);// replacing->(')
    

        6
  •  0
  •   staticsan    15 年前

    我想说,你最好下载JSON解码器的源代码(它们不是很大)并对其进行处理,特别是如果你知道你试图解码的JSON有什么问题的话。

    您提供的示例也需要{},这可能会有所帮助。

        7
  •  0
  •   trinalbadger587    3 年前

    这是我删除尾随/前导/多逗号的解决方案。它可以与删除单引号并在json键周围添加引号的其他答案结合使用。我意识到这与OP无关,因为它处理的是其他类型的无效json,但我只希望能帮助在谷歌搜索中发现这个问题的人。

    function replace_unquoted_text ($json, $f)
    {
      $matches = array();
      preg_match_all('/(")(?:(?=(\\\\?))\2.)*?\1/', $json, $matches, PREG_OFFSET_CAPTURE);
      //echo '<pre>' . json_encode($matches[0]) . '</pre>';
      $matchIndexes = [0];
      foreach ($matches[0] as $match)
      {
        array_push($matchIndexes, $match[1]);
        array_push($matchIndexes, strlen($match[0]) + $match[1]);
      }
      array_push($matchIndexes, strlen($json));
      $components = [];
      for ($n = 0; $n < count($matchIndexes); $n += 2)
      {
        $startIDX = $matchIndexes[$n];
        $finalExclIDX = $matchIndexes[$n + 1];
        //echo $startIDX . ' -> ' . $finalExclIDX . '<br>';
        $len = $finalExclIDX - $startIDX;
        if ($len === 0) continue;
        $prevIDX = ($n === 0) ? 0 : $matchIndexes[$n - 1];
        array_push($components, substr($json, $prevIDX, $startIDX - $prevIDX));
        array_push($components, $f(substr($json, $startIDX, $len)));
        array_push($components, substr($json, $finalExclIDX, ((($n + 1) === count($matchIndexes)) ? count($json) : $matchIndexes[$n + 1]) - $finalExclIDX));
      }
      //echo '<pre>' . json_encode($components) . '</pre>';
      return implode("", $components);
    }
    function json_decode_lazy ($jsonSnip) {
        return json_decode(fix_lazy_json($jsonSnip));
    }
    
    function fix_lazy_json ($json) {
        return replace_unquoted_text($json, 'fix_lazy_snip');
    }
    function fix_lazy_snip ($jsonSnip) {
        return remove_multi_commas_snip(remove_leading_commas_snip(remove_trailing_commas_snip($jsonSnip)));
    }
    
    function remove_leading_commas ($json) {
        return replace_unquoted_text($json, 'remove_leading_commas_snip');
    }
    function remove_leading_commas_snip ($jsonSnip) {
      return preg_replace('/([{[]\s*)(,\s*)*/', '$1', $jsonSnip);
    }
    
    function remove_trailing_commas ($json) {
        return replace_unquoted_text($json, 'remove_trailing_commas_snip');
    }
    function remove_trailing_commas_snip ($jsonSnip) {
      return preg_replace('/(,\s*)*,(\s*[}\]])/', '$2', $jsonSnip);
    }
    
    function remove_multi_commas ($json) {
        return replace_unquoted_text($json, 'remove_multi_commas_snip');
    }
    function remove_multi_commas_snip ($jsonSnip) {
      return preg_replace('/(,\s*)+,/', ',', $jsonSnip);
    }
    
    json_decode_lazy('[,,{,,,"a":17,,, "b":13,,,,},,,]') // {"a":17, "b":13}
    

    再见 repl.it