我正在提取无效JSON的JSON Feed。它完全没有引用。我尝试过一些事情,比如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
那里有没有可以处理无效JSON的JSON解析器吗?
编辑:我正在尝试在此字符串上使用json_decode()
。它什么都不返回。
答案 0 :(得分:10)
"
而不是单引号'
。function my_json_decode($s) { $s = str_replace( array('"', "'"), array('\"', '"'), $s ); $s = preg_replace('/(\w+):/i', '"\1":', $s); return json_decode(sprintf('{%s}', $s)); }
答案 1 :(得分:5)
根据我的经验,Marko的答案不再适用。对于较新的php版本,请使用以下内容:
$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);
答案 2 :(得分:3)
这个正则表达式可以解决这个问题
$json = preg_replace('/([{,])(\s*)([A-Za-z0-9_\-]+?)\s*:/','$1"$3":',$json);
答案 3 :(得分:1)
$json = preg_replace('/([{,])(\s*)([A-Za-z0-9_\-]+?)\s*:/','$1"$3":',$json);// adding->(")
$json = str_replace("'",'"', $json);// replacing->(')
这个解决方案似乎足以满足大多数常见目的。
答案 4 :(得分:1)
我知道这个问题已经过时了,但我希望这会对某人有所帮助。
我遇到了类似的问题,因为我想接受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)
}
答案 5 :(得分:0)
我认为你最好的选择是下载JSON解码器的源代码(它们并不大)并且操作它,特别是如果你知道你试图解码的JSON有什么问题。
您提供的示例也需要{},这可能会有所帮助。
答案 6 :(得分:0)
这是我删除尾随/前导/多逗号的解决方案。它可以与删除单引号并在 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。