Files

83 lines
2.8 KiB
Python

"""
Various functios to process files and work with regexps and Replacement objects
"""
import re
import logging
from collections.abc import Iterable
from pathlib import Path
from typing import cast, Sequence, Union, Optional
logger = logging.getLogger(__name__)
# This is a generic type that's a regexp with its replacement (it needs to be mutatable but we should
# add a lot of the below functionality to the class itself, for example we could have __call__ call the
# regex.match, we could make a function that configures the replacement based on a dictionary, we could
# make a function that executes the replacement on a string, etc. It would probably make the below code
# a bit less type dependent).
# FIXME implement path limiting
class Replacement:
def __init__(self, regexp, replacement, path=None):
self.regexp = regexp
self.replacement = replacement
self.path = path
def one_matches(relist: Sequence[Union[re.Pattern, Replacement, Sequence]], s: str) -> Union[None, re.Pattern, Replacement, Sequence]:
"""
Return True if one of the regular expressions, patterns, or 0th elements in Sequence of lists matches.
"""
for reg in relist:
if isinstance(reg, Replacement):
r = reg.regexp
elif isinstance(reg, re.Pattern):
r = reg
elif isinstance(reg, Iterable):
r = reg[0]
else:
raise Exception("got a weird thing")
if r.match(s):
return reg
return None
def apply_regexps(relist: Sequence[Replacement], exceptlist: Optional[Sequence[re.Pattern]]=None, s: str = "", debuglist: Optional[Sequence[re.Pattern]]=None) -> str:
"""
Return the string after applying each Replacement in the list passed as relist.
"""
if debuglist is None:
debuglist = []
if exceptlist is None:
exceptlist = []
res = s
debug = False
if one_matches(debuglist, s):
debug = True
logger.debug(f"-- regexp start {s}")
while True:
m: Replacement = cast(Replacement, one_matches(relist, res))
if debug and m is not None:
logger.debug(m)
if m is None:
break;
if one_matches(exceptlist, res):
if debug:
logger.debug("exceptlist: "+str(one_matches(exceptlist, res)))
break
res = m.regexp.sub(m.replacement, res)
if debug:
logger.debug(f"-- regexp done {res}")
return res
def process_text_file(relist: Sequence[Replacement], exceptlist: Sequence[re.Pattern], infile: Path, outfile: Path, debug_regexps: Sequence[re.Pattern] = None):
if debug_regexps is None:
debug_regexps = []
with infile.open("r") as inf, outfile.open("w") as outf:
fixedlines = [apply_regexps(relist, exceptlist, line, debug_regexps) for line in inf.readlines()]
outf.writelines(fixedlines)