Source code for nlcalc.calculator

from botify import Botify
from nlcalc.context import *
from nlcalc.utils import is_numeric, convert_to_numeric, text2int


[docs]class NLCalculator: """Natural Language Mathematical Calculator. This class can be used to parse mathematical statements in natural language. Attributes ---------- strict_mode_enabled """ def __init__(self): self._parser = Botify(is_token_data_callback=is_numeric, clean_data_callback=convert_to_numeric) self._init_tasks() self._init_modifiers() @property def strict_mode_enabled(self): """Whether strict mode is enabled for the calculator instance.""" return self._parser.strict_mode_enabled @strict_mode_enabled.setter def strict_mode_enabled(self, value): self._parser.strict_mode_enabled = value def _init_tasks(self): # Addition self._parser.add_task(keywords=('sum', 'summation', 'add', 'addition', 'total'), context=CONTEXT_SUM, rule=(1, 2)) self._parser.add_task(keywords=('added',), context=CONTEXT_SUM, rule=(-2, -1)) self._parser.add_task(keywords=('plus', '+'), context=CONTEXT_SUM, rule=(-1, 1)) # Subtraction self._parser.add_task(keywords=('difference', 'subtract', 'subtraction'), context=CONTEXT_DIFF, rule=(1, 2)) self._parser.add_task(keywords=('subtracted',), context=CONTEXT_DIFF, rule=(-2, -1)) self._parser.add_task(keywords=('minus', '-'), context=CONTEXT_DIFF, rule=(-1, 1)) # Multiplication self._parser.add_task(keywords=('product', 'multiply', 'multiplication'), context=CONTEXT_MUL, rule=(1, 2)) self._parser.add_task(keywords=('into', 'times', '*'), context=CONTEXT_MUL, rule=(-1, 1)) self._parser.add_task(keywords=('multiplied',), context=CONTEXT_MUL, rule=(-2, -1)) # Division self._parser.add_task(keywords=('divide', 'division'), context=CONTEXT_DIV, rule=(1, 2)) self._parser.add_task(keywords=('divided', 'over', '/'), context=CONTEXT_DIV, rule=(-1, 1)) # Factorial self._parser.add_task(keywords=('factorial',), context=CONTEXT_FACT, rule=(-1,)) # Exponent self._parser.add_task(keywords=('power', '^', '**'), context=CONTEXT_POW, rule=(-1, 1)) # Square self._parser.add_task(keywords=('square', 'squared'), context=CONTEXT_SQR, rule=(-1,)) # Cube self._parser.add_task(keywords=('cube', 'cubed'), context=CONTEXT_CUBE, rule=(-1,)) # Root self._parser.add_task(keywords=('root',), context=CONTEXT_SQRT, rule=(1,)) # Special Constants self._parser.add_task(keywords=('pi',), # pi context=CONTEXT_PI, rule=()) self._parser.add_task(keywords=('e',), # e context=CONTEXT_E, rule=()) def _init_modifiers(self): self._parser.add_modifier(modifier='to', keywords=('added', 'multiplied'), relative_pos=-1, action=Botify.ACTION_UPDATE_RULE, parameter=(-1, 1)) self._parser.add_modifier(modifier='with', keywords=('added', 'multiplied'), relative_pos=-1, action=Botify.ACTION_UPDATE_RULE, parameter=(-1, 1)) self._parser.add_modifier(modifier='of', keywords=('factorial', 'square', 'cube'), relative_pos=-1, action=Botify.ACTION_UPDATE_RULE, parameter=(1,)) self._parser.add_modifier(modifier='by', keywords=('divide', 'divided', 'multiply', 'multiplied'), relative_pos=-1, action=Botify.ACTION_UPDATE_RULE, parameter=(-1, 1)) self._parser.add_modifier(modifier='from', keywords=('subtract',), relative_pos=-2, action=Botify.ACTION_UPDATE_RULE, parameter=(2, 1)) self._parser.add_modifier(modifier='from', keywords=('subtracted',), relative_pos=-1, action=Botify.ACTION_UPDATE_RULE, parameter=(1, -1)) self._parser.add_modifier(modifier='root', keywords=('square', 'cube'), relative_pos=-2, action=Botify.ACTION_UPDATE_RULE, parameter=(1,)) self._parser.add_modifier(modifier='root', keywords=('square',), relative_pos=-2, action=Botify.ACTION_UPDATE_CONTEXT, parameter=CONTEXT_SQRT) self._parser.add_modifier(modifier='root', keywords=('cube',), relative_pos=-2, action=Botify.ACTION_UPDATE_CONTEXT, parameter=CONTEXT_CUBE_ROOT) self._parser.add_modifier(modifier='root', keywords=('square', 'cube'), relative_pos=-2, action=Botify.ACTION_DELETE, parameter=1)
[docs] def calculate(self, text): """Calculate the output after parsing input. Parameters ---------- text : str A string value which should be parsed Returns ------- int or float: The final result Raises ------ ValueError If the text cannot be succesfully parsed and evaluated to get a result. """ res = self._parser.parse(text2int(text)) if len(res) == 1: return res[0] else: raise ValueError("Unable to Parse")
def main(): m = NLCalculator() while True: print(m.calculate(input("---> "))) print(m._parser._get_report()) if __name__ == '__main__': main()