diff options
Diffstat (limited to 'src/utils/parse/sed.py')
| -rw-r--r-- | src/utils/parse/sed.py | 73 |
1 files changed, 73 insertions, 0 deletions
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 |
