From 29f0a282a8efb9ea93d33670ad42f1c151f70243 Mon Sep 17 00:00:00 2001 From: jesopo Date: Sun, 9 Feb 2020 10:49:10 +0000 Subject: add utils.parse.sed. --- src/utils/parse/__init__.py | 3 +- src/utils/parse/sed.py | 73 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 src/utils/parse/sed.py (limited to 'src') diff --git a/src/utils/parse/__init__.py b/src/utils/parse/__init__.py index cf32d8f5..dd13ecbc 100644 --- a/src/utils/parse/__init__.py +++ b/src/utils/parse/__init__.py @@ -1,9 +1,10 @@ -import decimal, io, typing +import decimal, io, re, typing from src.utils import datetime, errors from .spec import * from .time import duration from .types import try_int +from . import sed COMMENT_TYPES = ["#", "//"] def hashflags(filename: str diff --git a/src/utils/parse/sed.py b/src/utils/parse/sed.py new file mode 100644 index 00000000..96234063 --- /dev/null +++ b/src/utils/parse/sed.py @@ -0,0 +1,73 @@ +import dataclasses, re, typing + +class Sed(object): + type: str + def match(self, s: str) -> typing.Optional[str]: + return None + +@dataclasses.dataclass +class SedReplace(Sed): + type: str + pattern: typing.Pattern + replace: str + count: int + + def match(self, s): + return self.pattern.sub(self.replace, s, self.count) + +@dataclasses.dataclass +class SedMatch(Sed): + type: str + pattern: typing.Pattern + + def match(self, s): + match = self.pattern.search(s) + if match: + return match.group(0) + return None + +def _sed_split(s): + backslash = False + forward_slash = [] + for i, c in enumerate(s): + if not backslash: + if c == "/": + forward_slash.append(i) + if c == "\\": + backslash = True + else: + backslash = False + if forward_slash and (not forward_slash[-1] == (len(s)-1)): + forward_slash.append(len(s)) + + last = 0 + out = [] + for i in forward_slash: + out.append(s[last:i]) + last = i+1 + return out + +def _sed_flags(s: str) -> typing.Tuple[int, int]: + count = 1 + re_flags = 0 + if "g" in s: + count = 0 + if "i" in s: + re_flags |= re.I + return count, re_flags + +def parse_sed(sed_s: str) -> typing.Optional[Sed]: + type, pattern, *args = _sed_split(sed_s) + if type == "s": + replace, *args = args + count, flags = _sed_flags((args or [""])[0]) + pattern = re.compile(pattern, flags) + return SedReplace(type, pattern, replace, count) + elif type == "m": + count, flags = _sed_flags((args or [""])[0]) + return SedMatch(type, re.compile(pattern, flags)) + return None + +def sed(sed_obj: Sed, s: str) -> typing.Tuple[str, typing.Optional[str]]: + out = sed_obj.match(s) + return sed_obj.type, out -- cgit v1.3.1-10-gc9f91