diff options
author | Adrián Oliva <adrian.oliva@cimat.mx> | 2023-05-08 21:31:09 -0600 |
---|---|---|
committer | Adrián Oliva <adrian.oliva@cimat.mx> | 2023-05-08 21:31:09 -0600 |
commit | ca65b3836eaa5b026b3f13afdd7ad3b8b192e9a4 (patch) | |
tree | 86e55759380d38c92b47f124bd051c3ecfccd089 /utils | |
parent | 269eee248d24acbb12f13ab519dfbe1c881d3bb8 (diff) | |
download | Ledger.py-ca65b3836eaa5b026b3f13afdd7ad3b8b192e9a4.tar.gz Ledger.py-ca65b3836eaa5b026b3f13afdd7ad3b8b192e9a4.zip |
First attempt at sorting accounts.
I DID IT!! I'm really happy with the result. :')
Diffstat (limited to '')
-rw-r--r-- | utils/acc_regex.py | 105 | ||||
-rw-r--r-- | utils/acc_regex_test.py | 17 |
2 files changed, 122 insertions, 0 deletions
diff --git a/utils/acc_regex.py b/utils/acc_regex.py new file mode 100644 index 0000000..1c85def --- /dev/null +++ b/utils/acc_regex.py @@ -0,0 +1,105 @@ +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 diff --git a/utils/acc_regex_test.py b/utils/acc_regex_test.py new file mode 100644 index 0000000..309d83a --- /dev/null +++ b/utils/acc_regex_test.py @@ -0,0 +1,17 @@ +import acc_regex +import unittest + + +class test_create_ors(unittest.TestCase): + def test_create_ors(self): + self.assertEqual(acc_regex.create_ors('Rent Transportation'), 'Rent or Transportation') + self.assertEqual(acc_regex.create_ors('Income and Job'), 'Income and Job') + self.assertEqual(acc_regex.create_ors('Radio and (Judge Police)'), 'Radio and (Judge or Police)') + + self.assertEqual(acc_regex.create_ors('(Telephone not Beach) not House'), '(Telephone or not Beach) or not House') + + self.assertEqual(acc_regex.create_ors('Run'), 'Run') + + +if __name__ == '__main__': + unittest.main() |