'Truncate long strings inside json in python
Given some json
[
{
"default_value": "True",
"feature_name": "feature_1",
"active_on": "remote_1,remote_2,remote_3,remote_4,remote_5,remote_6,remote_7"
},
{
"feature_name": "special_super_duper_feature_wooooooooot",
"active_on": "remote_2"
}
]
how do I truncate values longer than, say, 20 chars:
[
{
"default_value": "True",
"feature_name": "feature_1",
"active_on": "remote_1,remote_2..."
},
{
"feature_name": "special_super_dup...",
"active_on": "remote_2"
}
]
as generically as possible?
EDIT: Here's a more generic example to fit:
[
{
"a": {"b": "c"},
"d": "e"
},
{
"a": [{"b": "dugin-walrus-blowing-up-the-view-and-ruining-page-frame"}]
}
]
The endgame here is to make "pretty-print" for arbitrary json. I'm wondering whether there's a nice way to do that using only standard library.
Solution 1:[1]
Here's my take on it:
import collections
...
def truncate_strings(obj: collections.abc.Iterable, truncate: int, suffix: str = "...") -> int:
"""
@param obj: generic iterable - object to truncate. Implemented for dicts and lists.
Extensible by adding new types to isinstance.
@param truncate: int - total str length to be set. value 0 to disable.
@param suffix: str [Optional] - the truncation string suffix
@returns count: int - number of strings truncated
"""
if not truncate or not obj or isinstance(obj, str):
return 0
count = 0
if isinstance(obj, dict):
for key_ in obj.keys():
if not key_:
return 0
if isinstance(obj.get(key_), str):
if len(obj[key_]) > truncate - len(suffix):
count += 1
obj[key_] = obj[key_][:truncate - len(suffix)] + suffix
else:
count += truncate_strings(key_, truncate, suffix)
elif isinstance(obj, collections.abc.Iterable):
for item in obj:
count += truncate_strings(item, truncate, suffix)
return count
Note this func is recursive on iterables, so a long list will kill your call stack. Should work on reasonable size jsons though (tested on 1k items json array)
Solution 2:[2]
You can work with a string limiter this way:
[:17] + '...'
And work from loop in your values to readjust its values.
Example:
a = 'test text to work with limiter length'
a = a[:17] + '...'
print(a)
Result:
test text to work...
Solution 3:[3]
I'm not aware of any built-in method to do this, but one approach might be to just iterated over the list, then over the items in each dictionary, and apply a string slice to each item, like so:
def truncate(d: dict):
for k, v in d.items():
d.update({k: str(v)[:17] + "..."})
return d
json_trunc = list(map(lambda x: truncate(x), json_orig))
It would definitely be possible to include the truncating function in the list comprehension too if desired, I've just separated them here for readability / understandability.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Toma |
Solution 2 | Digital Farmer |
Solution 3 |