Przycinanie białych spacji zarówno w kluczu obiektu, jak i wartości rekurencyjnie

Jak przyciąć białe spacje w kluczach i wartościach obiektu JavaScript rekurencyjnie?

Natknąłem się na jeden problem, w którym próbowałem "wyczyścić" dostarczony przez użytkownika ciąg JSON i wysłać go do innego kodu do dalszego przetwarzania.

Załóżmy, że mamy dostarczony przez użytkownika łańcuch JSON, którego klucz właściwości i wartość są typu "string". Jednak problematyczne w tym przypadku jest to, że klucze i wartości nie są tak czyste, jak chcesz. Powiedz a { " key_with_leading_n_trailing_spaces": "my_value_with_leading_spaces"}.

W tym przypadku, może łatwo spowodować problem z genialnie napisany program JavaScript próbuje korzystać z takich danych (lub powinniśmy nazwać to brudne dane?) ponieważ gdy twój kod próbuje uzyskać wartość z tego obiektu JSON, nie tylko klucz nie jest dopasowany, ale także wartość nie może być dopasowana. Rozejrzałem się po google i znalazłem kilka wskazówek, ale nie ma jednego lekarstwa, które go leczy wszystkie.

Biorąc pod uwagę ten JSON z dużą ilością białych spacji w kluczach i wartościach.

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   "}
    }
  ]

};
Tak więc to właśnie wymyśliłem (z pomocą 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));

Uwaga: zrobiłem to w 1, 2 krokach, ponieważ nie mogłem znaleźć lepszego ujęcia, aby poradzić sobie z tym wszystkim. Jeśli jest problem w moim kodzie lub coś lepszego, Proszę podzielić się z nami.

Dzięki!
Author: vichsu, 2015-11-04

4 answers

Możesz wyczyścić nazwy właściwości i atrybuty za pomocą obiektu .keys aby uzyskać tablicę kluczy, następnie Array.prototyp.zmniejsz , aby iterować nad kluczami i utworzyć nowy obiekt z przyciętymi kluczami i wartościami. Funkcja musi być rekurencyjna, aby przycinała zagnieżdżone obiekty i tablice.

Zauważ, że dotyczy tylko zwykłych tablic i obiektów, jeśli chcesz radzić sobie z innymi typami obiektów, wywołanie reduce musi być bardziej wyrafinowane, aby Określ typ obiektu (np. odpowiednio przemyślaną wersję 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)? []:{});
}
 17
Author: RobG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-03 23:41:04

Możesz po prostu stringify it, string replace, and reparse it

JSON.parse(JSON.stringify(badJson).replace(/"\s+|\s+"/g,'"'))
 29
Author: epascarello,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-03 22:59:37

ODPOWIEDŹ Epascarello powyżej plus kilka testów jednostkowych (dla pewności):

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
Author: Richard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-02 09:00:08

Podobne do odpowiedzi epascarello. Tak zrobiłem:

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;
}

Przypadki testowe

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
Author: some random guy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-04 02:14:57