使用PHP解析JSON无效

gijlo24d  于 2023-10-21  发布在  PHP
关注(0)|答案(7)|浏览(124)

我正在提取一个无效的JSON提要。完全没有引号。我尝试了一些方法,比如explode()str_replace(),让字符串看起来更像有效的JSON,但是如果里面有一个关联的JSON字符串,它通常会被搞砸。
下面是一个示例:

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

有没有PHP的JSON解析器可以处理像这样的无效JSON?
编辑:我尝试在这个字符串上使用json_decode()。它什么也不返回。

qgelzfjb

qgelzfjb1#

1.所有的引号都应该是双引号",而不是单引号'
1.所有的键都应该加引号。
1.整个元素应该是一个对象。

function my_json_decode($s) {
        $s = str_replace(
            array('"',  "'"),
            array('\"', '"'),
            $s
        );
        $s = preg_replace('/(\w+):/i', '"\1":', $s);
        return json_decode(sprintf('{%s}', $s));
    }
uttx8gqw

uttx8gqw2#

这个正则表达式就可以了

$json = preg_replace('/([{,])(\s*)([A-Za-z0-9_\-]+?)\s*:/','$1"$3":',$json);
km0tfn4u

km0tfn4u3#

根据我的经验,马尔科的答案不再起作用了。对于较新的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);
q3aa0525

q3aa05254#

我知道这个问题很老了,但我希望这对某人有帮助。
我也有类似的问题,我想接受JSON作为用户输入,但又不想在每个键上都加上冗长的“引号”。此外,我也不想在值周围加上引号,但仍然要解析有效的数字。
最简单的方法似乎是编写一个自定义解析器。
我想出了这个,它解析为嵌套的关联/索引数组:

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)
}
kb5ga3dv

kb5ga3dv5#

$json = preg_replace('/([{,])(\s*)([A-Za-z0-9_\-]+?)\s*:/','$1"$3":',$json);// adding->(")
$json = str_replace("'",'"', $json);// replacing->(')

这个解决方案似乎足以满足大多数常见的目的。

tvz2xvvm

tvz2xvvm6#

我认为你最好的办法是下载JSON解码器的源代码(它们并不庞大)并摆弄它,特别是如果你知道你试图解码的JSON有什么问题的话。
您提供的示例也需要{ },这可能会有所帮助。

abithluo

abithluo7#

这是我删除trailing/leading/multi-comms的解决方案。它可以与其他答案组合,删除单引号并在json键周围添加引号。我意识到这与OP无关,因为它处理其他类型的无效JSON,但我只是希望帮助那些在Google搜索中找到这个问题的人。

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.它。

相关问题