13

ネイティブブラウザの実装を使用してjsonから解析しているオブジェクトがいくつかあります。オブジェクトのプロパティの一部は数値です。今のところ、数値はjsonから文字列として解析され、parseIntを使用して文字列を必要なintにキャストします。

問題は、これを行う23個のオブジェクトと、次のようなintに解析している全体で約80個のプロパティがあることです。

if (TheObject && TheObject.TheProperty) {
   TheObject.TheProperty = parseInt(TheObject.TheProperty, 10);
}

非常によく似たコード行がたくさんあります。プロトタイプなどを使用してJSON.parse関数の動作を変更し、パーサーが実行されるたびに文字列プロパティが実際にintであるかどうかを確認し、実際にintとしてキャストする方法はありますか?

ありがとう。

4

5 に答える 5

14

JSON.parse後処理を実行できる関数の形式で2番目の引数を受け入れます。

JSON.parse('{"p": "5"}', function(k, v) { 
    return (typeof v === "object" || isNaN(v)) ? v : parseInt(v, 10); 
});

すべての数値文字列を処理したくない場合は、必要なプロパティのルックアップテーブルを作成します。

var props = {"p":1, "some_prop":1, "another_prop":1};

JSON.parse('{"p": "5"}', function(k, v) { 
    return props.hasOwnProperty(k) ? parseInt(v, 10) : v; 
});
于 2012-05-12T13:00:33.860 に答える
9

JSONは次のように数値を処理できます。

{
    "TheObject":{
        "TheProperty":5
    }
}

プロパティが二重引用符で囲まれている場合、それは文字列です。それ以外の場合は、数値、ブール値(trueおよびfalse値)、nullまたは解析エラーの原因となるものです。

http://json.org/を参照してください

于 2012-05-12T12:49:49.740 に答える
4

データソースを修正できない場合(数値は文字列ではなく数値として渡す必要があります)、処理中に各アイテムを受け取る「リバイバー」関数を渡すことができます。JSON.parseこれにより、変換するオプションが提供されます。

// Create this once
var propsToConvert = {
    TheProperty: 1,
    TheOtherProperty: 1,
    YetAnotherProperty: 1,
    // ...and so on...
};

// Use it each time you parse
var obj = JSON.parse(str, function(key, value) {
    if (propsToConvert.hasOwnProperty(key)) {
        return parseInt(value, 10);
    }
    return value;
});

実例| ソース

または、プロパティ名が十分に一意でない場合(のプロパティである場合は、必ずしも処理する必要はありThePropertyません)、2レベルのチェックとしてこれを行うことができます。TheObject

// Define the object names and their property names (once)
var propsToConvert = {
    TheObject: {
        TheProperty: 1,
        TheOtherProperty: 1,
        YetAnotherProperty: 1,
        // ...and so on...
    },
    AnotherObject: {
        // Other properties...
    }
};

// Use it each time you parse
var obj = JSON.parse(str, function(key, value) {
    var name, props;

    if (typeof value === "object") {
        props = propsToConvert[key];
        if (props) {
            for (name in props) {
                value[name] = parseInt(value[name], 10);
            }
        }
    }
});

(リバイバーは裏返しに呼び出されるため、オブジェクトのキーが表示されるまでにプロパティはオブジェクト上にあります。そのため、プロパティはその場で更新されます。)

あなたはその考えを理解します、あなたがリバイバー機能でできることはたくさんあります。


補足:parseInt私が上で使用したものは、かなり寛容です—おそらくあなたが望むよりも寛容です。例えば:

var a = parseInt('1a', 10); // 1, instead of NaN

"0x10"16進数として扱われるような文字列で問題がない場合は、次のようにします。

var a = Number(str);

...NaN無効な数値文字列(Number("1a")is NaN)が表示されます。JSONは16進数を使用することを意図していないため、壊れたデータソースがそれらを16進数としてエンコードしないことが確実であれば、あなたは黄金です。

それ以外の場合、10進数が必要であるが厳密にしたい場合は、文字列に対して正規表現を実行して、有効な10進数のパターンと一致することを確認する必要があります(すべてのものをサポートする場合は、かなり複雑です)。 JavaScript数値リテラルのサポート)。

于 2012-05-12T13:01:14.480 に答える
2

パーサーを変更できるとは思いませんが、多くの同様のコード行の代わりに、プロパティの配列を使用して、それら[]へのループ内の表記でそれらにアクセスしparseInt()ます。もちろん、JSONを生成するコードにアクセスできる場合は、引用符で囲まれていないintを適切に出力するように変更する方が簡単です。

// Array of properties you want to parse out
var parseUs = ['prop1','prop2','prop3','prop4'];

// Array of objects you need to parse them in
var objs = [obj1, obj2, obj3];

// Iterate over the objects
for (var i=0; i<objs.length; i++) {

  // And over the properties array
  for (var j=0; j<parseUs.length; j++) {
    // Parse out the int value if the object has the property
    if (objs[i].hasOwnProperty(parseUs[j]) {
      objs[i][parseUs[j]] = parseInt(parseUs[j], 10);
    }
  }
}

:これは、オブジェクトがすべてのオブジェクトでint値ではないプロパティ名を共有している場合は機能しません。その場合は、オブジェクトごとにプロパティの配列を使用するようにこれを変更する必要があります。

于 2012-05-12T12:50:21.147 に答える
1

@kbecは正解です。データソースを制御できない場合は、次のようなものを使用できます。

function intify(obj, fields) {
  if (typeof(obj) == "undefined") return;
  var numFields = fields.length;
  for (var i = 0; i < numFields; i++) {
    var field = fields[i];
    if (typeof(obj[field]) != "undefined") {
      obj[field] = parseInt(obj[field], 10);
    }
  }
  return obj;
}

intify(obj, ['foo', 'bar']);
intify(obj.baz, ['boo']);
于 2012-05-12T12:53:06.653 に答える