137 lines
4 KiB
Python
137 lines
4 KiB
Python
# From https://github.com/linjackson78/jstyleson/blob/8c47cc9e665b3b1744cccfaa7a650de5f3c575dd/jstyleson.py
|
|
# License https://github.com/linjackson78/jstyleson/blob/8c47cc9e665b3b1744cccfaa7a650de5f3c575dd/LICENSE
|
|
import json
|
|
|
|
|
|
def dispose(json_str):
|
|
"""Clear all comments in json_str.
|
|
|
|
Clear JS-style comments like // and /**/ in json_str.
|
|
Accept a str or unicode as input.
|
|
|
|
Args:
|
|
json_str: A json string of str or unicode to clean up comment
|
|
|
|
Returns:
|
|
str: The str without comments (or unicode if you pass in unicode)
|
|
"""
|
|
result_str = list(json_str)
|
|
escaped = False
|
|
normal = True
|
|
sl_comment = False
|
|
ml_comment = False
|
|
quoted = False
|
|
|
|
a_step_from_comment = False
|
|
a_step_from_comment_away = False
|
|
|
|
former_index = None
|
|
|
|
for index, char in enumerate(json_str):
|
|
if escaped: # We have just met a '\'
|
|
escaped = False
|
|
continue
|
|
|
|
if a_step_from_comment: # We have just met a '/'
|
|
if char != "/" and char != "*":
|
|
a_step_from_comment = False
|
|
normal = True
|
|
continue
|
|
|
|
if a_step_from_comment_away: # We have just met a '*'
|
|
if char != "/":
|
|
a_step_from_comment_away = False
|
|
|
|
if char == '"':
|
|
if normal and not escaped:
|
|
# We are now in a string
|
|
quoted = True
|
|
normal = False
|
|
elif quoted and not escaped:
|
|
# We are now out of a string
|
|
quoted = False
|
|
normal = True
|
|
|
|
elif char == "\\":
|
|
# '\' should not take effect in comment
|
|
if normal or quoted:
|
|
escaped = True
|
|
|
|
elif char == "/":
|
|
if a_step_from_comment:
|
|
# Now we are in single line comment
|
|
a_step_from_comment = False
|
|
sl_comment = True
|
|
normal = False
|
|
former_index = index - 1
|
|
elif a_step_from_comment_away:
|
|
# Now we are out of comment
|
|
a_step_from_comment_away = False
|
|
normal = True
|
|
ml_comment = False
|
|
for i in range(former_index, index + 1):
|
|
result_str[i] = ""
|
|
|
|
elif normal:
|
|
# Now we are just one step away from comment
|
|
a_step_from_comment = True
|
|
normal = False
|
|
|
|
elif char == "*":
|
|
if a_step_from_comment:
|
|
# We are now in multi-line comment
|
|
a_step_from_comment = False
|
|
ml_comment = True
|
|
normal = False
|
|
former_index = index - 1
|
|
elif ml_comment:
|
|
a_step_from_comment_away = True
|
|
elif char == "\n":
|
|
if sl_comment:
|
|
sl_comment = False
|
|
normal = True
|
|
for i in range(former_index, index + 1):
|
|
result_str[i] = ""
|
|
elif char == "]" or char == "}":
|
|
if normal:
|
|
_remove_last_comma(result_str, index)
|
|
|
|
# To remove single line comment which is the last line of json
|
|
if sl_comment:
|
|
sl_comment = False
|
|
normal = True
|
|
for i in range(former_index, len(json_str)):
|
|
result_str[i] = ""
|
|
|
|
# Show respect to original input if we are in python2
|
|
return ("" if isinstance(json_str, str) else "").join(result_str)
|
|
|
|
|
|
# There may be performance suffer backtracking the last comma
|
|
def _remove_last_comma(str_list, before_index):
|
|
i = before_index - 1
|
|
while str_list[i].isspace() or not str_list[i]:
|
|
i -= 1
|
|
|
|
# This is the first none space char before before_index
|
|
if str_list[i] == ",":
|
|
str_list[i] = ""
|
|
|
|
|
|
# Below are just some wrapper function around the standard json module.
|
|
|
|
|
|
def loads(text, **kwargs):
|
|
return json.loads(dispose(text), **kwargs)
|
|
|
|
|
|
def load(fp, **kwargs):
|
|
return loads(fp.read(), **kwargs)
|
|
|
|
|
|
def dumps(obj, **kwargs):
|
|
return json.dumps(obj, **kwargs)
|
|
|
|
|
|
def dump(obj, fp, **kwargs):
|
|
json.dump(obj, fp, **kwargs)
|