2015-11-03 69 views
9

如何以递归方式修剪JavaScript对象中的键和值中的空格?以递归方式修剪对象键和值中的空白

我遇到了一个问题,我试图“清理”用户提供的JSON字符串并将其发送到我的其他代码中以供进一步处理。

比方说,我们有一个用户提供的JSON字符串,其属性键和值的类型为“string”。然而,在这种情况下有什么问题是键和值不够干净。说一个{“key_with_leading_n_trailing_spaces”:“my_value_with_leading_spaces”}。

在这种情况下,它可能很容易导致您的精彩编写的JavaScript程序试图利用这些数据(或者我们应该把它称为脏数据?)的问题,因为当你的代码试图从这个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个步骤,因为我无法找到一个更好地解决一切问题。如果我的代码存在问题或其他问题,请与我们分享。

谢谢!

+1

技术上它不是JSON。 – epascarello

+0

由于您正在讨论JavaScript对象字面值而不是JSON,因此删除了json标记。 –

+0

谢谢,epascarello,我可能不会使用这个术语,但这是一个简单的JavaScript对象。如果您不介意,请让我知道它不适合作为JSON对象。 – vichsu

回答

15

可以清理属性名称和使用Object.keys属性来拿到钥匙的数组,然后阵列。 prototype.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)? []:{}); 
} 
+0

Thanks,@ RobG。这个效果很好! 我只是想知道为什么我们必须编写代码来处理这样的问题。为什么本地JS默认的方法是这样的? – vichsu

+0

有一个[* TC39邮件列表*](https ://mail.mozilla.org/pipermail/es-discuss/)。去吧。;-) – RobG

21

你可以只字符串化它,字符串替换和重新分析它

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

这看起来不错!谢谢,epascarello!这看起来非常简洁。 – vichsu

+0

如果对象中存在引号,例如:{“key”:'and“let”it'},则Stringify将会转义它们,但正则表达式将剥去这些引号的空白,产生'和'让它'。由于JS没有负向倒序,你可以用一个函数来解决这个问题:'JSON.parse(JSON.stringify(badJson).replace(/(\\)?“\ s * | \ s +”/ g,($ 0 ,$ 1)=> $ 1?$ 0:'''))' – SamGoody

+0

您也可以使用替换函数和'JSON.stringify'来检查值是否为字符串,如果是则修剪它。 https://codepen.io/ajmueller/pen/NyXNME)。我相信这可以针对性能进行优化,但它很容易阅读,有点简洁,并且对于合理大小的对象应该表现得很好。 –

2

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