Обрезать пробелы как в ключе объекта, так и в значении рекурсивно
Как обрезать пробелы как в ключах, так и в значениях объекта JavaScript рекурсивно?
я столкнулся с одной проблемой, в которой я пытался "очистить" предоставленную пользователем строку JSON и отправить ее в другой код для дальнейшей обработки.
предположим, у нас есть пользовательская строка JSON, ключ свойства и значение которой имеют тип "string". Однако в этом случае проблема заключается в том, что ключи и значения не так чисты, как хотелось бы. Скажи: { " key_with_leading_n_trailing_spaces ": "my_value_with_leading_spaces" }.
в этом случае это может легко вызвать проблему с вашей блестяще написанной программой JavaScript, пытающейся использовать такие данные (или мы должны называть это грязными данными?) потому что, когда ваш код пытается получить значение из этого объекта JSON, не только ключ не соответствует, но и значение не может быть сопоставлено. Я посмотрел вокруг google и нашел несколько советов, но нет ни одного лекарства, которое вылечит его все.
учитывая этот 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 "}
}
]
};
Так вот что я придумал ( с помощью лодашь.в 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 шага, потому что я не мог найти лучший выстрел, чтобы справиться со всем этим решением. Если есть проблема в моем коде или что-нибудь лучше, пожалуйста, поделитесь с нами.
спасибо!
4 ответов
вы можете очистить имена свойств и атрибуты с помощью чтобы получить массив ключей, затем массив.прототип.уменьшить для итерации по клавишам и создания нового объекта с обрезанными ключами и значениями. Функция должна быть рекурсивной, чтобы она также обрезала вложенные объекты и массивы.
обратите внимание, что он имеет дело только с простыми массивами и объектами, если вы хотите иметь дело с другими типами объектов, вызов уменьшить должен быть более сложный для определения типа объекта (например, подходящая умная версия новый объект.конструктор()).
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)? []:{});
}
вы можете просто stringify его, string replace и reparse
JSON.parse(JSON.stringify(badJson).replace(/"\s+|\s+"/g,'"'))
ответ 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' }]}));
похоже на ответ epascarello. Вот что я сделал:--3-->
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 }"));