diff -ur v1/ezyaml.py v2/ezyaml.py --- v1/ezyaml.py 2018-08-29 13:48:48.000000000 +0900 +++ v2/ezyaml.py 2018-08-30 22:20:21.000000000 +0900 @@ -3,13 +3,55 @@ import sys def err(t, s): - sys.stderr.write('err {} "{}\n"'.format(t, s)) + sys.stderr.write('err {} "{}"\n'.format(t, s)) sys.exit(1) +qts = ('"', "'") + +def parse(s): + lst = [''] + in_esc = False + qt = None + + while s: + (c, s) = ( s[:1], s[1:] ) + + if not in_esc and c == '\\': + esc = True + continue + if in_esc: + in_esc = False + lst[-1] += c + continue + if qt: + if c in qts: + lst[-1] += c + lst += '' + qt = None + continue + elif c in qts: + qt = c + if lst[-1]: + lst += '' + lst[-1] += c + + while len(lst) > 1 and lst[-1] == '': + lst.pop() + return lst + +def find_colon_idx(s): + idx = 0 + lst = parse(s) + for s in lst: + if ( s[:1] not in qts ) and ( ':' in s ): + return idx + s.index(':') + idx += len(s) + return -1 + def get_kind(s): if s.startswith('- '): return 'list' - if ':' in s: + if find_colon_idx(s) >= 0: return 'dict' return 'other' @@ -28,22 +70,23 @@ if idt_ == idt+2: return get_dict(idt_, lines) elif idt_ > idt: - err('indent', s) + err('indent dict', s) elif kind_ == 'list': if idt_ == idt+2 or idt_ == idt: return get_list(idt_, lines) elif idt_ > idt: - err('indent', s) + err('indent list', s) else: if idt_ == idt+2: return get_other(idt_, lines) elif idt_ >= idt: - err('indent', s) + err('indent other', s) return None def get_dict(idt, lines): s = lines.pop(0)[idt:] - (k, v) = s.split(':') + idx = find_colon_idx(s) + (k, v) = ( s[:idx], s[idx+1:] ) k = get_value( k.strip() ) v = get_value( v.strip() ) @@ -81,8 +124,8 @@ except ValueError: pass - (h, t) = ( s[:1], s[-1:] ) - if h == t and h in ('"', "'"): + lst = parse(s) + if len(lst) == 1 and s[:1] in qts: s = s[1:-1] return s @@ -135,10 +178,18 @@ return '\n'.join(lines) def dump_value(obj): - s = '{}'.format(obj) - if type(obj) == str and type( get_value(s) ) != str: - s = "'" + s + "'" - return s + if type(obj) == str: + s = obj + (q2, q1, cl) = map( lambda t: t in s, ('"', "'", ':') ) + if q2 and q1: + s = s.replace("'", "\\'") + q1 = False + if q2 or q1 or cl: + qt = '"' if q1 else "'" + s = qt + s + qt + return s + + return '{}'.format(obj) def dump_other(obj, idt): return (' ' * idt) + dump_value(obj) @@ -156,8 +207,9 @@ if __name__ == "__main__": obj = load( sys.stdin.read() ) - print('load obj\n{}'.format(obj)) s = dump(obj) - print('dump\n{}'.format(s)) + print(s) + + sys.stderr.write( '{}\n'.format(obj) ) # EOF