5

JSON 形式のデータ フィードを取得していますが、これは使用可能な唯一の形式です。PHPでjson_decodeを使ってJSONをデコードしているのですが、壊れていて、人のニックネームに二重引用符があるところにJSONが生成されていることがわかりました。http://jsonformatter.curiousconcept.comを使用してこれを確認しました。

データの作成を制御することはできませんが、この壊れた形式が発生した場合は対処する必要があります。解析後のこのデータは、MySQL TABLE に入れられます。

例えば:

"contact1": "David "Dave" Letterman",

json_decode は NULL を返します。ファイルを手動で保存し、Dave のニックネームを一重引用符で囲むと、すべてが機能しました。

$json_string = file_get_contents($json_download);
$json_array = json_decode($json_string, true);

json_decode によって処理される前に、json_string の破損した JSON 形式を修正するにはどうすればよいですか? ファイルを前処理し、ニックネームの二重引用符をバックスラッシュするにはどうすればよいですか? またはそれらを単一引用符に変更しますか? このような二重引用符を MySQL に保存することは良い考えですか?

これが各データ フィードでいつ発生するかはわかりません。そのため、contact1 を修正するための内側の二重引用符があるかどうかだけを確認する必要はありません。上記の例のような行を取得し、外側の二重引用符を除くコロンの後のすべてをバックスラッシュする方法は PHP にありますか? ありがとう!

これは、tftd が提供する正しいコードです。

<?php
// This:
// "contact1": "David "Dave" Letterman",
// Needs to look like this to be decoded by JSON:
// "contact1": "David \"Dave\" Letterman",

$data ='"contact1": "David "Dave" Letterman",';
function replace($match){
    $key = trim($match[1]);
    $val = trim($match[2]);

    if($val[0] == '"')
        $val = '"'.addslashes(substr($val, 1, -1)).'"';
    else if($val[0] == "'")
        $val = "'".addslashes(substr($val, 1, -1))."'";

    return $key.": ".$val;
}
$preg = preg_replace_callback("#([^{:]*):([^,}]*)#i",'replace',$data);
var_dump($preg);
$json_array = json_decode($preg);
var_dump($json_array);
echo $json_array . "\n";
echo $preg . "\n";
?>

出力は次のとおりです。

string(39) ""contact1": "David \"Dave\" Letterman","
NULL

"contact1": "David \"Dave\" Letterman",
4

5 に答える 5

8

私は独自の jsonFixer() 関数を持っています - それは2つのステップで動作します: ガベージの削除 (一貫性のないフォーマットを均等にするため) と再フォーマットです。

<?php
  function jsonFixer($json){
    $patterns     = [];
    /** garbage removal */
    $patterns[0]  = "/([\s:,\{}\[\]])\s*'([^:,\{}\[\]]*)'\s*([\s:,\{}\[\]])/"; //Find any character except colons, commas, curly and square brackets surrounded or not by spaces preceded and followed by spaces, colons, commas, curly or square brackets...
    $patterns[1]  = '/([^\s:,\{}\[\]]*)\{([^\s:,\{}\[\]]*)/'; //Find any left curly brackets surrounded or not by one or more of any character except spaces, colons, commas, curly and square brackets...
    $patterns[2]  =  "/([^\s:,\{}\[\]]+)}/"; //Find any right curly brackets preceded by one or more of any character except spaces, colons, commas, curly and square brackets...
    $patterns[3]  = "/(}),\s*/"; //JSON.parse() doesn't allow trailing commas
    /** reformatting */
    $patterns[4]  = '/([^\s:,\{}\[\]]+\s*)*[^\s:,\{}\[\]]+/'; //Find or not one or more of any character except spaces, colons, commas, curly and square brackets followed by one or more of any character except spaces, colons, commas, curly and square brackets...
    $patterns[5]  = '/["\']+([^"\':,\{}\[\]]*)["\']+/'; //Find one or more of quotation marks or/and apostrophes surrounding any character except colons, commas, curly and square brackets...
    $patterns[6]  = '/(")([^\s:,\{}\[\]]+)(")(\s+([^\s:,\{}\[\]]+))/'; //Find or not one or more of any character except spaces, colons, commas, curly and square brackets surrounded by quotation marks followed by one or more spaces and  one or more of any character except spaces, colons, commas, curly and square brackets...
    $patterns[7]  = "/(')([^\s:,\{}\[\]]+)(')(\s+([^\s:,\{}\[\]]+))/"; //Find or not one or more of any character except spaces, colons, commas, curly and square brackets surrounded by apostrophes followed by one or more spaces and  one or more of any character except spaces, colons, commas, curly and square brackets...
    $patterns[8]  = '/(})(")/'; //Find any right curly brackets followed by quotation marks...
    $patterns[9]  = '/,\s+(})/'; //Find any comma followed by one or more spaces and a right curly bracket...
    $patterns[10] = '/\s+/'; //Find one or more spaces...
    $patterns[11] = '/^\s+/'; //Find one or more spaces at start of string...

    $replacements     = [];
    /** garbage removal */
    $replacements[0]  = '$1 "$2" $3'; //...and put quotation marks surrounded by spaces between them;
    $replacements[1]  = '$1 { $2'; //...and put spaces between them;
    $replacements[2]  = '$1 }'; //...and put a space between them;
    $replacements[3]  = '$1'; //...so, remove trailing commas of any right curly brackets;
    /** reformatting */
    $replacements[4]  = '"$0"'; //...and put quotation marks surrounding them;
    $replacements[5]  = '"$1"'; //...and replace by single quotation marks;
    $replacements[6]  = '\\$1$2\\$3$4'; //...and add back slashes to its quotation marks;
    $replacements[7]  = '\\$1$2\\$3$4'; //...and add back slashes to its apostrophes;
    $replacements[8]  = '$1, $2'; //...and put a comma followed by a space character between them;
    $replacements[9]  = ' $1'; //...and replace by a space followed by a right curly bracket;
    $replacements[10] = ' '; //...and replace by one space;
    $replacements[11] = ''; //...and remove it.

    $result = preg_replace($patterns, $replacements, $json);

    return $result;
  }
?>

使用例:

<?php
  // Received badly formatted json:
  // {"contact1": "David "Dave" Letterman", price : 30.00, 'details' : "Greatest 'Hits' Album"}
  $json_string = '{"contact1": "David "Dave" Letterman", price : 30.00, \'details\' : "Greatest \'Hits\' Album"}';
  jsonFixer($json_string);
?>

結果:

{"contact1": "David \"Dave\" Letterman", "price" : "30.00", "details" : "Greatest \'Hits\' Album"}

注: これは、形式が不適切な可能性のあるすべての JSON 文字列でテストされたわけではありませんが、複雑な複数レベルの JSON 文字列で使用し、それまではうまく機能しています。

于 2016-02-17T04:20:31.223 に答える
3

他の人がすでに指摘しているように、JSON フォーマットの問題についてクライアントに伝えるのが最善です。元の開発者/会社にバグレポートを送信して修正できるように依頼してください。彼/彼らがそれを修正できない場合は、解決策を提供してください。addslashesその前に文字列が必要ですjson_encode

何らかの理由fixで書式設定が必要になった場合は、次の方法が適しています。

$data = '"contact1": "David "Dave" Letterman", "contact2": "Peter "Robert" Smith",{\'test\': \'working "something"\'}';
function replace($match){
    $key = trim($match[1]);
    $val = trim($match[2]);

    if($val[0] == '"')
        $val = '"'.addslashes(substr($val, 1, -1)).'"';
    else if($val[0] == "'")
        $val = "'".addslashes(substr($val, 1, -1))."'";

    return $key.": ".$val;
}
$preg = preg_replace_callback("#([^{:]*):([^,}]*)#i",'replace',$data);
var_dump($preg);
// string '"contact1": "David \"Dave\" Letterman", "contact2": "Peter \"Robert\" Smith",{'test': 'working \"something\"'}' (length=110)

誰かが再び json 形式を台無しにすると、これが壊れる可能性があることに注意してください。

于 2012-11-05T18:06:44.333 に答える
0

出力前に文字列をエスケープするように伝えます。修正を申し出たり、コード ソリューションを提供したりすることもできます。

それ以外の場合は、正規表現で preg_replace を使用できます

テキスト内の指定された二重引用符を preg_replace に置き換えるを参照してください

于 2012-11-05T17:12:38.890 に答える
0

他の人が言ったように、検索と置換を行うことはできますが、難しいのはあいまい一致ルールを作成することです。これを解析するには、いくつかのことを想定する必要があるためです。おそらく、次のいずれかを想定する必要があります。

1a) キーにコロンが含まれていない
1b) またはキーの引用符が適切にエスケープされ
ている
2a) 値にコンマが含まれていない
2b) または値に適切にエスケープされた引用符がある。

それでも、解析が混乱する状況に陥る可能性があり、JSON にコメントがあるとさらに悪化します。(準拠していませんが、非常に一般的です。)

現在、データに応じて、改行を使用して新しいキーを見ているかどうかを判断できますが、これも信頼できず、大きな仮定を立て始めます。

つまり、簡単に言えば、いつでも間違っている可能性のあるいくつかの仮定を立てるか、データを修正するためにそれらを入手する必要があります。

于 2012-11-05T17:17:07.177 に答える