import regex class RegexMoveToCol: def __init__(self, match: str, to: str, with_input_iteration: list[str]|None = None): self.match = match self.to = to if with_input_iteration is not None and type(with_input_iteration) != list: with_input_iteration = list(map([e] for e in with_input_iteration)) self.with_input_iteration = with_input_iteration self.__operation_input_depth = self.__find_operation_input_depth() def __find_operation_input_depth(self): if not self.with_input_iteration: return None return max(len(option) for option in self.__iteration_input_depth()) @staticmethod def _get_merged_groups(regex_pattern: str, entry: str) -> str: match = regex.search(regex_pattern, entry.value) if not match: return "" return "".join(g for g in match.groups() if g is not None) @staticmethod def _remove_regex_groups(regex_pattern: str, entry: str) -> str: match = regex.search(regex_pattern, entry.value) if not match: return entry.value spans = [s for s in match.spans()[1:] if s != (-1, -1)] result = [] last = 0 for start, end in sorted(spans): result.append(entry.value[last:start]) last = end result.append(entry.value[last:]) return "".join(result) def do_changes(self, source_coll: str, used_regex: str, row: dict[str, str], changes={}): changes[self.to] = self._get_merged_groups(used_regex, row[source_coll]) changes[source_coll] = self._remove_regex_groups(used_regex, row[source_coll]) return changes def execute_on_row(self, row: dict[str, str], source_coll: str = None): if not source_coll: raise ValueError("source_col required") if self.with_input_iteration: changes = None used_regex = self.match for iteration in self.with_input_iteration: for operation_id in range(0, self.__operation_input_depth-1): used_regex.replace(f"{{{{ {operation_id} }}}}", iteration.get(operation_id)) changes = self.do_changes(source_coll, used_regex, row, changes) return changes else: return self.do_changes(source_coll, self.match, row)