diff --git a/hjson/__init__.py b/hjson/__init__.py index f1f6642..101b7d4 100644 --- a/hjson/__init__.py +++ b/hjson/__init__.py @@ -49,6 +49,7 @@ __author__ = 'Christian Zangl ' from decimal import Decimal +import re from .scanner import HjsonDecodeError from .decoder import HjsonDecoder @@ -640,3 +641,137 @@ def simple_first(kv): elements to the top, then container elements. """ return (isinstance(kv[1], (list, dict, tuple)), kv[0]) + + +def loadWithComments(fp, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None, + object_pairs_hook=None, use_decimal=False, **kw): + """ + returns Tuple[Dict[str, Any], List[Tuple[str, str, str, int]]] + A tuple containing the comment, + the previous line's text, + the next line's text, + the string index of the comment + """ + jsonString = fp.read() + return loadsWithComments(jsonString, encoding=encoding, cls=cls, object_hook=object_hook, parse_float=parse_float, + parse_int=parse_int, object_pairs_hook=object_pairs_hook, use_decimal=use_decimal, **kw) + + +def loadsWithComments(jsonString, encoding=None, cls=None, object_hook=None, parse_float=None, + parse_int=None, object_pairs_hook=None, use_decimal=False, **kw): + """ + returns Tuple[Dict[str, Any], List[Tuple[str, str, str, int]]] + A tuple containing the comment, + the previous line's text, + the next line's text, + the string index of the comment + """ + + jsonObject = loads(jsonString, encoding=encoding, cls=cls, object_hook=object_hook, parse_float=parse_float, + parse_int=parse_int, object_pairs_hook=object_pairs_hook, use_decimal=use_decimal, **kw) + + commentPositions = [] + comments = re.findall(r"(\s+//.*)|(\s+#.*)|(\s+/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)", jsonString) + for found in comments: + for comment in found: + if comment != '': + prevLine = '' + nextLine = '' + commentIndex = jsonString.find(comment) + commentEndIndex = commentIndex + len(comment) + + prevNewLineIndex = jsonString.rfind('\n', 0, commentIndex + 1) + prevNewLineIndex = 0 if prevNewLineIndex == -1 else prevNewLineIndex + prevPrevNewLineIndex = jsonString.rfind('\n', 0, prevNewLineIndex) + prevPrevNewLineIndex = 0 if prevPrevNewLineIndex == -1 else prevPrevNewLineIndex + if prevNewLineIndex == 0 and prevPrevNewLineIndex == 0: + prevLine = '{' + else: + prevLine = jsonString[prevPrevNewLineIndex:prevNewLineIndex] + prevLine = prevLine.replace('\n', '') + + nextNewLineIndex = jsonString.find('\n', commentEndIndex) + nextNewLineIndex = len(jsonString) if nextNewLineIndex == -1 else nextNewLineIndex + nextNextNewLineIndex = jsonString.find('\n', nextNewLineIndex + 1) + nextNextNewLineIndex = len(jsonString) if nextNextNewLineIndex == -1 else nextNextNewLineIndex + if nextNewLineIndex == len(jsonString) and nextNextNewLineIndex == len(jsonString): + nextLine = '}' + else: + nextLine = jsonString[nextNewLineIndex:nextNextNewLineIndex] + nextLine = nextLine.replace('\n', '') + + commentPositions.append((comment[1:], prevLine, nextLine, commentIndex)) + if comment != '': + prevLine = '' + nextLine = '' + commentIndex = jsonString.find(comment) + commentEndIndex = commentIndex + len(comment) + + prevNewLineIndex = jsonString.rfind('\n', 0, commentIndex + 1) + prevNewLineIndex = 0 if prevNewLineIndex == -1 else prevNewLineIndex + prevPrevNewLineIndex = jsonString.rfind('\n', 0, prevNewLineIndex) + prevPrevNewLineIndex = 0 if prevPrevNewLineIndex == -1 else prevPrevNewLineIndex + if prevNewLineIndex == 0 and prevPrevNewLineIndex == 0: + prevLine = '{' + else: + prevLine = jsonString[prevPrevNewLineIndex:prevNewLineIndex] + prevLine = prevLine.replace('\n', '') + + nextNewLineIndex = jsonString.find('\n', commentEndIndex) + nextNewLineIndex = len(jsonString) if nextNewLineIndex == -1 else nextNewLineIndex + nextNextNewLineIndex = jsonString.find('\n', nextNewLineIndex + 1) + nextNextNewLineIndex = len(jsonString) if nextNextNewLineIndex == -1 else nextNextNewLineIndex + if nextNewLineIndex == len(jsonString) and nextNextNewLineIndex == len(jsonString): + nextLine = '}' + else: + nextLine = jsonString[nextNewLineIndex:nextNextNewLineIndex] + nextLine = nextLine.replace('\n', '') + + commentPositions.append((comment[1:], prevLine, nextLine, commentIndex)) + + return jsonObject, commentPositions + + +def dumpWithComments(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, cls=None, indent=None, + encoding='utf-8', default=None, use_decimal=True, namedtuple_as_object=True, tuple_as_array=True, + bigint_as_string=False, sort_keys=False, item_sort_key=None, for_json=False, + int_as_string_bitcount=None, **kw): + + hjsonString = dumpsWithComments(obj, skipkeys=skipkeys, ensure_ascii=ensure_ascii, check_circular=check_circular, + cls=cls, encoding=encoding, default=default, use_decimal=use_decimal, + namedtuple_as_object=namedtuple_as_object, tuple_as_array=tuple_as_array, + bigint_as_string=bigint_as_string, sort_keys=sort_keys, item_sort_key=item_sort_key, + for_json=for_json, int_as_string_bitcount=int_as_string_bitcount, **kw) + fp.write(hjsonString) + + +def dumpsWithComments(obj, commentPositions, skipkeys=False, ensure_ascii=True, check_circular=True, + cls=None, encoding='utf-8', default=None, use_decimal=True, namedtuple_as_object=True, + tuple_as_array=True, bigint_as_string=False, sort_keys=False, item_sort_key=None, + for_json=False, int_as_string_bitcount=None, **kw): + + hjsonString = dumps(obj, skipkeys=skipkeys, ensure_ascii=ensure_ascii, check_circular=check_circular, + cls=cls, encoding=encoding, default=default, use_decimal=use_decimal, + namedtuple_as_object=namedtuple_as_object, tuple_as_array=tuple_as_array, + bigint_as_string=bigint_as_string, sort_keys=sort_keys, item_sort_key=item_sort_key, + for_json=for_json, int_as_string_bitcount=int_as_string_bitcount, indent=' ', **kw) + prevPrevLineIndex = 0 + prevNextLineIndex = 0 + for comments in commentPositions: + comment = comments[0] + prevLine = comments[1] + commentIndex = comments[3] + if ':' in prevLine: + prevLine = prevLine[:prevLine.find(':') + 1] + nextLine = comments[2] + if ':' in nextLine: + nextLine = nextLine[:nextLine.find(':') + 1] + # Find where previous line begins + prevLineIndex = hjsonString.rfind(prevLine, prevPrevLineIndex, commentIndex) + # Find next \n char after previous line beginning + newlineCharAfterPrevLineIndex = hjsonString.find('\n', prevLineIndex) + nextLineIndex = hjsonString.find(nextLine, prevNextLineIndex) + hjsonString = hjsonString[:newlineCharAfterPrevLineIndex + 1] + comment + '\n' + hjsonString[nextLineIndex:] + prevPrevLineIndex = prevLineIndex + prevNextLineIndex = nextLineIndex + return hjsonString