3from typing
import Tuple
5TskvRow = Dict[str, str]
8_EQUALS_OR_BACKSLASH = re.compile(
'=|\\\\')
19def _search_equals_or_backslash(s: str, start: int) -> int:
20 match = _EQUALS_OR_BACKSLASH.search(s, start)
22 return match.start()
if match
else -1
25def _search_backslash(s: str, start: int) -> int:
26 return s.find(
'\\', start)
29def _parse_pair(pair: str) -> Tuple[str, str]:
30 search_fn = _search_equals_or_backslash
35 end = search_fn(pair, start)
37 unescaped_part += pair[start:end]
41 search_fn = _search_backslash
42 elif end + 1 != len(pair)
and pair[end + 1]
in _UNESCAPED_CHARS:
43 unescaped_part += _UNESCAPED_CHARS[pair[end + 1]]
46 unescaped_part +=
'\\'
49 end = search_fn(pair, start)
51 unescaped_part += pair[start:]
54 raise RuntimeError(f
'Invalid tskv pair: {pair}')
56 return key, unescaped_part
59def parse_line(line: str) -> TskvRow:
60 parts = line.rstrip(
'\n').split(
'\t')
61 if parts[:1] != [
'tskv']:
62 raise RuntimeError(f
'Invalid tskv line: {line!r}')
63 return dict(map(_parse_pair, parts[1:]))