How do you trim white spaces in both the keys and values in a JavaScript Object recursively?
I came across one issue in which I was trying to \"clean\" a user suppli
The best solution I used is this. Check the documentation on replacer function.
var obj = {"data": {"address": {"city": "\n \r New York", "country": " USA \n\n\r"}}};
var trimmed = JSON.stringify(obj, (key, value) => {
if (typeof value === 'string') {
return value.trim();
}
return value;
});
console.log(JSON.parse(trimmed));
You can just stringify it, string replace, and reparse it
JSON.parse(JSON.stringify(badJson).replace(/"\s+|\s+"/g,'"'))
epascarello's answer above plus some unit tests (just for me to be sure):
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' }]}));
I tried the solution JSON.stringify solution above, but it will not work with a string like '"this is \'my\' test"'. You can get around it using stringify's replacer function and just trim the values going in.
JSON.parse(JSON.stringify(obj, (key, value) => (typeof value === 'string' ? value.trim() : value)))
@RobG Thank you for the solution. Adding one more condition will not create more nested objects
function trimObj(obj) {
if (obj === null && !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() : typeof obj[key] === 'object' ? trimObj(obj[key]) : obj[key];
return acc;
}, Array.isArray(obj)? []:{});
}
Similar to epascarello's answer. This is what I did :
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;
}
Test cases
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 }"));