web-dev-qa-db-ja.com

オブジェクトキーと値の両方の空白を再帰的に削除する

JavaScriptオブジェクトのキーと値の両方の空白を再帰的にどのようにトリミングしますか?

ユーザーが指定したJSON文字列を「クリーン」にし、他のコードに送信してさらに処理しようとする問題に遭遇しました。

プロパティキーと値が「文字列」タイプのユーザー指定のJSON文字列があるとします。ただし、この場合の問題は、キーと値が必要なほどきれいではないことです。 {"key_with_leading_n_trailing_spaces": "my_value_with_leading_spaces"}と言います。

この場合、あなたのコードがこのJSONオブジェクトから値を取得しようとしているときだけでなくキーは一致しませんが、値も一致できません。私はグーグルの周りを見回して、いくつかのヒントを見つけましたが、それをすべて治す一つの治療法はありません。

キーと値に多くの空白があるこのJSONを考えます。

var badJson = {
  "  some-key   ": "    let it go    ",
  "  mypuppy     ": "    donrio   ",
  "   age  ": "   12.3",
  "  children      ": [
    { 
      "   color": " yellow",
      "name    ": "    alice"
    },    { 
      "   color": " silver        ",
      "name    ": "    bruce"
    },    { 
      "   color": " brown       ",
      "     name    ": "    francis"
    },    { 
      "   color": " red",
      "      name    ": "    york"
    },

  ],
  "     house": [
    {
      "   name": "    mylovelyhouse     ",
      " address      " : { "number" : 2343, "road    "  : "   boardway", "city      " : "   Lexiton   "}
    }
  ]

};

これが私が思いついたものです(lodash.jsを使用して):

//I made this function to "recursively" hunt down keys that may 
//contain leading and trailing white spaces
function trimKeys(targetObj) {

  _.forEach(targetObj, function(value, key) {

      if(_.isString(key)){
        var newKey = key.trim();
        if (newKey !== key) {
            targetObj[newKey] = value;
            delete targetObj[key];
        }

        if(_.isArray(targetObj[newKey]) || _.isObject(targetObj[newKey])){
            trimKeys(targetObj[newKey]);
        }
      }else{

        if(_.isArray(targetObj[key]) || _.isObject(targetObj[key])){
            trimKeys(targetObj[key]);
        }
      }
   });

}

//I stringify this is just to show it in a bad state
var badJson = JSON.stringify(badJson);

console.log(badJson);

//now it is partially fixed with value of string type trimed
badJson = JSON.parse(badJson,function(key,value){
    if(typeof value === 'string'){
        return value.trim();
    }
    return value;
});

trimKeys(badJson);

console.log(JSON.stringify(badJson));

ここで注意してください:すべての解決策を処理するためのより良いワンショットを見つけることができなかったため、これを1、2ステップで実行しました。私のコードまたはそれ以上の問題に問題がある場合は、私たちと共有してください。

ありがとう!

14
vichsu

Object.keysを使用してプロパティ名と属性をクリーンアップしてキーの配列を取得し、次にArray.prototype.reduceを使用してキーを反復処理して新しいトリミングされたキーと値を持つオブジェクト。関数は、ネストされたオブジェクトと配列もトリムするように再帰的である必要があります。

それはプレーンな配列とオブジェクトのみを処理することに注意してください。他のタイプのオブジェクトを処理したい場合、オブジェクトのタイプを決定するためにreduceへの呼び出しはより洗練されている必要があります(例えば適切な賢いバージョン) new obj.constructor())の。

function trimObj(obj) {
  if (!Array.isArray(obj) && typeof obj != 'object') return obj;
  return Object.keys(obj).reduce(function(acc, key) {
    acc[key.trim()] = typeof obj[key] == 'string'? obj[key].trim() : trimObj(obj[key]);
    return acc;
  }, Array.isArray(obj)? []:{});
}
20
RobG

あなたはそれを文字列化し、文字列を置き換え、そして再解析することができます

JSON.parse(JSON.stringify(badJson).replace(/"\s+|\s+"/g,'"'))
31
epascarello

上記のepascarelloの回答といくつかの単体テスト(私が確認するためだけに):

function trimAllFieldsInObjectAndChildren(o: any) {
  return JSON.parse(JSON.stringify(o).replace(/"\s+|\s+"/g, '"'));
}

import * as _ from 'lodash';
assert.true(_.isEqual(trimAllFieldsInObjectAndChildren(' bob '), 'bob'));
assert.true(_.isEqual(trimAllFieldsInObjectAndChildren('2 '), '2'));
assert.true(_.isEqual(trimAllFieldsInObjectAndChildren(['2 ', ' bob ']), ['2', 'bob']));
assert.true(_.isEqual(trimAllFieldsInObjectAndChildren({'b ': ' bob '}), {'b': 'bob'}));
assert.true(_.isEqual(trimAllFieldsInObjectAndChildren({'b ': ' bob ', 'c': 5, d: true }), {'b': 'bob', 'c': 5, d: true}));
assert.true(_.isEqual(trimAllFieldsInObjectAndChildren({'b ': ' bob ', 'c': {' d': 'alica c c '}}), {'b': 'bob', 'c': {'d': 'alica c c'}}));
assert.true(_.isEqual(trimAllFieldsInObjectAndChildren({'a ': ' bob ', 'b': {'c ': {'d': 'e '}}}), {'a': 'bob', 'b': {'c': {'d': 'e'}}}));
assert.true(_.isEqual(trimAllFieldsInObjectAndChildren({'a ': ' bob ', 'b': [{'c ': {'d': 'e '}}, {' f ': ' g ' }]}), {'a': 'bob', 'b': [{'c': {'d': 'e'}}, {'f': 'g' }]}));
3
Richard

エパスカレッロの答えに似ています。これは私がやったことです:

import Java.util.regex.Matcher;
import Java.util.regex.Pattern;

........

public String trimWhiteSpaceAroundBoundary(String inputJson) {
    String result;
    final String regex = "\"\\s+|\\s+\"";
    final Pattern pattern = Pattern.compile(regex);
    final Matcher matcher = pattern.matcher(inputJson.trim());
    // replacing the pattern twice to cover the Edge case of extra white space around ','
    result = pattern.matcher(matcher.replaceAll("\"")).replaceAll("\"");
    return result;
}

テストケース

assertEquals("\"2\"", trimWhiteSpace("\" 2 \""));
assertEquals("2", trimWhiteSpace(" 2 "));
assertEquals("{   }", trimWhiteSpace("   {   }   "));
assertEquals("\"bob\"", trimWhiteSpace("\" bob \""));
assertEquals("[\"2\",\"bob\"]", trimWhiteSpace("[\"  2  \",  \"  bob  \"]"));
assertEquals("{\"b\":\"bob\",\"c c\": 5,\"d\": true }",
              trimWhiteSpace("{\"b \": \" bob \", \"c c\": 5, \"d\": true }"));
0
some random guy