【问题标题】:PHP reading invalid json with json_decode();PHP 使用 json_decode() 读取无效的 json;
【发布时间】:2012-07-30 20:27:37
【问题描述】:

我有无效的外部 json 数据,名称周围没有双引号。

例子:

{
  data: [
    {
      idx: 0,
      id: "0",
      url: "http://247wallst.com/",
      a: [
        {
          t: "Title",
          u: "http://247wallst.com/2012/07/30/",
          sp: "About"
        }
      ],
      doc_id: "9386093612452939480"
    },
    {
      idx: 1,
      id: "-1"
    }
  ],
  results_per_page: 10,
  total_number_of_news: 76,
  news_per_month: [20, 0, 8, 1, 1, 2, 0, 2, 1, 0, 0, 1, 1, 0, 5, 1, 1, 1, 0, 2, 5, 16, 7, 1],
  result_start_num: 2,
  result_end_num: 2,
  result_total_articles: 76
}

正如你看到的很多名称,如 data、idx、id、url 和其他名称都没有双引号,所以这使得这个 json 无效。 如何使这个外部 json 有效?我已经尝试过 str_replace,将 '{' 替换为 '{"' 并将 ':' 替换为 '":' 在不带引号的名称周围添加双引号,但这会弄乱一些已经双引号的变量。

如何使这个 json 有效,以便我可以使用 PHP json_decode 读取这些数据?我对 preg_replace 不是很熟悉..

有效的 json 格式如下:

{
  "data": [
    {
      "idx": 0,
      "id": "0",
      "url": "http://247wallst.com/",
      "a": [
        {
          "t": "Title",
          "u": "http://247wallst.com/2012/07/30/",
          "sp": "About"
        }
      ],
      "doc_id": "9386093612452939480"
    },
    {
      "idx": 1,
      "id": "-1"
    }
  ],
  "results_per_page": 10,
  "total_number_of_news": 76,
  "news_per_month": [20, 0, 8, 1, 1, 2, 0, 2, 1, 0, 0, 1, 1, 0, 5, 1, 1, 1, 0, 2, 5, 16, 7, 1],
  "result_start_num": 2,
  "result_end_num": 2,
  "result_total_articles": 76
}

请建议我一些 php preg_replace 函数。

数据来源: http://www.google.com/finance/company_news?q=aapl&output=json&start=1&num=1

【问题讨论】:

  • 这个数据是在哪里构建的?它是你控制的脚本吗?
  • 这可能不是特别有用,但是虽然您显示的不是有效的 JSON,但它 有效的 Javascript - 因此,如果您可以通过 Javascript 触发它,然后对其进行 JSON 编码再次,它会让你的生活变得很轻松。如果你有方便的 No​​de.js,这可以通过一个简单的exec() 调用来完成。虽然这并不是一个很好的长期解决方案。
  • 我不控制这个脚本的构建。

标签: php json


【解决方案1】:

使用preg_replace,您可以:

json_decode(preg_replace('#(?<pre>\{|\[|,)\s*(?<key>(?:\w|_)+)\s*:#im', '$1"$2":', $in));

由于上述示例不适用于真实数据(作战计划很少能在与敌人的第一次接触中幸存下来),因此我的第二个看法是:

$infile = 'http://www.google.com/finance/company_news?q=aapl&output=json&start=1&num=1';

// first, get rid of the \x26 and other encoded bytes.
$in = preg_replace_callback('/\\\x([0-9A-F]{2})/i',
    function($match){
        return chr(intval($match[1], 16));
    }, file_get_contents($infile));

$out = $in;

// find key candidates
preg_match_all('#(?<=\{|\[|,)\s*(?<key>(?:\w|_)+?)\s*:#im', $in, $m, PREG_OFFSET_CAPTURE);

$replaces_so_far = 0;
// check each candidate if its in a quoted string or not
foreach ($m['key'] as $match) {
    $position = $match[1] + ($replaces_so_far * 2); // every time you expand one key, offsets need to be shifted with 2 (for the two " chars)
    $key = $match[0];
    $quotes_before = preg_match_all('/(?<!\\\)"/', substr($out, 0, $position), $m2);
    if ($quotes_before % 2) { // not even number of not-escaped quotes, we are in quotes, ignore candidate
        continue;
    }
    $out = substr_replace($out, '"'.$key.'"', $position, strlen($key));
    ++$replaces_so_far;
}

var_export(json_decode($out, true));

但由于谷歌在 RSS 提要中提供此数据,如果它适用于您的用例,我建议您使用该数据,这只是为了好玩(-:

【讨论】:

  • 这就是我想要的!适用于一个元素,但不知何故无法解码多个元素(多个元素)无法读取google.com/finance/…
  • 在我看来,它在输入的t:"Apple, Samsung, Kodak, Imation: Intellectual Property" 部分失败了,我想你可以尝试破解正则表达式,但也许编写一个正确的解析会是一个更好的主意。
  • 我想通了!替换了几个转义字符,现在它可以工作 str_replace(array("\\x26","#39;"),array("","'"),$string);谢谢!
  • 我添加了一种据称更强大的方法来执行此操作,而不是单行,但可以在您的示例数据上正常工作。
  • 正如你上面提到的t:"Apple, Samsung, Kodak, Imation: Intellectual Property"-likish 值确实会导致错误。第二次采取你建议在我的服务器上的第 5 行失败,但我很理解你的想法。
【解决方案2】:

来自 Google 的 JSON 提要似乎总是受到问题的困扰——以某种形式或形式的格式不正确。如果您将提要切换为 RSS,您可以轻松地将其转换为数组或数组中的 JSON。

<?php

$contents = file_get_contents('http://www.google.com/finance/company_news?q=aapl&output=rss&start=1&num=1');

// Convert the RSS to an array (probably just use this)
$arr = simplexml_load_string($contents);

// Or if you specifically want JSON
$json = json_encode($arr);

// And back to an array
print_r(json_decode($json));

【讨论】:

  • 有趣的解决方案,但是每个元素的 [description] 值不正确。
猜你喜欢
  • 2012-10-16
  • 2011-01-25
  • 2014-09-29
  • 2020-03-18
  • 1970-01-01
  • 1970-01-01
  • 2012-05-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多