83 lines
2.8 KiB
Python
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)
|