2015-11-03 10 views
9

Come si ritagliano gli spazi bianchi sia in chiavi che in valori in un oggetto JavaScript in modo ricorsivo?Ridurre gli spazi bianchi sia nella chiave dell'oggetto che nel valore in modo ricorsivo

Mi sono imbattuto in un problema in cui stavo cercando di "pulire" una stringa JSON fornita dall'utente e inviarla nel mio altro codice per un'ulteriore elaborazione.

Diciamo che abbiamo una stringa JSON fornita dall'utente la cui chiave e valore di proprietà sono di tipo "stringa". Tuttavia, ciò che è problematico in questo caso è che le chiavi e i valori non sono così puliti come desiderato. Dì un {"key_with_leading_n_trailing_spaces": "my_value_with_leading_spaces"}.

In questo caso, può facilmente causare problemi con il tuo programma JavaScript brillantemente scritto cercando di utilizzare tali dati (o dovremmo chiamarli dati sporchi?) Perché quando il codice sta cercando di ottenere il valore da questo JSON oggetto, non solo la chiave non corrisponde ma anche il valore non può essere abbinato. Ho cercato su google e ho trovato alcuni suggerimenti, ma non esiste una cura che curerà tutto.

Dato questo JSON con molti spazi bianchi in chiavi e valori.

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

}; 

Quindi questo è ciò che mi si avvicinò con (con l'aiuto di usare 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)); 

Nota qui: ho fatto questo in 1, 2 passi perché non riuscivo a trovare un meglio uno scatto per affrontare tutta la soluzione. Se c'è un problema nel mio codice o qualcosa di meglio, si prega di condividere con noi.

Grazie!

+1

tecnicamente non è JSON. – epascarello

+0

Rimosso il tag json mentre si parla di un oggetto letterale javascript, non di JSON. –

+0

Grazie, epascarello, non posso usare il termine con precisione ma questo è un oggetto JavaScript banale. Se non ti dispiace, fammi sapere dove non è qualificato come oggetto JSON. – vichsu

risposta

15

È possibile pulire i nomi di proprietà e gli attributi utilizzando Object.keys per ottenere una serie di chiavi, quindi Array. prototype.reduce per iterare sulle chiavi e creare un nuovo oggetto con chiavi e valori tagliati. La funzione deve essere ricorsiva in modo da tagliare anche oggetti e matrici annidate.

Si noti che si tratta solo con array semplici e oggetti, se si vuole fare con altri tipi di oggetti, la chiamata a ridurre deve essere più sofisticato per determinare il tipo di oggetto (ad esempio una versione opportunamente intelligente di nuovo oggetto obj.constructor()). risposta

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)? []:{}); 
} 
+0

Grazie, @ RobG, questo funziona molto bene! Mi chiedo solo perché dobbiamo scrivere il codice per risolvere questo problema Perché il JS nativo non ha metodi come questo di default? – vichsu

+0

C'è una [* mailing list TC39 *] (https : //mail.mozilla.org/pipermail/es-discuss/). Vai per questo. ;-) – RobG

21

Si può solo stringa i essa, stringa di sostituire e rianalizzare si

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

Questo sembra abbastanza buono! Grazie, epascarello! Questo sembra essere molto conciso. – vichsu

+0

Se all'interno dell'oggetto ci sono citazioni, ad es .: {"chiave": 'e "lascia" it'}, Stringify le sfuggirà, ma la regex rimuoverà anche gli spazi bianchi attorno a quelli, producendo "e" lasciandolo ". Poiché JS non ha lookbehind negativi, puoi risolverlo con una funzione: 'JSON.parse (JSON.stringify (badJson) .replace (/ (\\)?" \ S * | \ s + "/ g, ($ 0 , $ 1) => $ 1? $ 0: '"'))' – SamGoody

+0

Si può anche usare una funzione replacer con 'JSON.stringify' che controlla se il valore è una stringa e lo ritaglia se lo è. Vedi [this CodePen] (https://codepen.io/ajmueller/pen/NyXNME). Sono sicuro che questo potrebbe essere ottimizzato per le prestazioni, ma è piuttosto facile da leggere, piuttosto conciso, e dovrebbe funzionare bene per oggetti di dimensioni ragionevoli. –

2

di epascarello sopra oltre ad alcuni test di unità (solo per me per essere sicuri):

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' }]})); 
Problemi correlati