from typing import List from utils.read_file import entry from utils.register import complete_prices import re RE_NOT = r'not ((?:[^()\s]+)|(?:\(.+\)))' RE_AND = r'((?:[^()\s]+)|(?:\(.+\))) and ((?:[^()\s]+)|(?:\(.+\)))' RE_OR = r'((?:[^()\s]+)|(?:\(.+\))) or ((?:[^()\s]+)|(?:\(.+\)))' def clean_pattern(pattern: str): pattern = pattern.strip() if pattern[0] == '(' and pattern[-1] == ')': pattern = pattern[1:-1] return pattern def create_ors(string: str): splitted = string.split() result = '' for left, right in zip(splitted[:-1], splitted[1:]): if left not in ['not', 'and', 'or'] and right not in ['and', 'or']: result += f'{left} or ' else: result += f'{left} ' result += splitted[-1] return result def find_logic_patt(pattern: str): # First search for the pattern "not {text}" patt = re.findall(RE_NOT, pattern) if patt: return ('not', patt[0]) # If there wasn't a "not" pattern, try searching for "{text 1} or {text 2}" patt = re.findall(RE_OR, pattern) if patt: return ('or', patt[0]) # Lastly, try searching for "{text 1} and {text 2}" pattern. patt = re.findall(RE_AND, pattern) if patt: return ('and', patt[0]) # If there wasn't any pattern, return None. return (None, None) def re_ledger(pattern: str, account_name: str): pattern = clean_pattern(pattern) if ' ' not in pattern: if pattern == '{False}': return False elif pattern == '{True}': return True elif re.search(pattern, account_name) is None: return False else: return True pattern = create_ors(pattern) key, patt = find_logic_patt(pattern) while key is not None: if key == 'not': meets_criteria = not re_ledger(patt, account_name) pattern = pattern.replace(f'not {patt}', f'{{{meets_criteria}}}') elif key == 'or': meets_criteria = re_ledger(patt[0], account_name) or re_ledger(patt[1], account_name) pattern = pattern.replace(f'{patt[0]} or {patt[1]}', f'{{{meets_criteria}}}') elif key == 'and': meets_criteria = re_ledger(patt[0], account_name) and re_ledger(patt[1], account_name) pattern = pattern.replace(f'{patt[0]} and {patt[1]}', f'{{{meets_criteria}}}') key, patt = find_logic_patt(pattern) return re_ledger(pattern, account_name) def filter_accounts(arguments: List[str], my_entries: List[entry]): pattern = ' '.join(arguments) result = [] for ent in my_entries: complete_prices(ent) for trans in ent.transactions: if re_ledger(pattern, trans[0]): result.append(entry( date=ent.date.strftime('%Y-%m-%d'), comment=ent.comment, transactions=[[trans[0], str(trans[1])]] )) return result