Last active
July 6, 2023 19:30
-
-
Save PeterMinin/c8711f482dafbb1ff40b to your computer and use it in GitHub Desktop.
A command-line calculator with some handy and/or neat features.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
""" | |
A command line calculator with the following features: | |
1) Accepts numbers with any decimal and thousand separators. | |
2) Uses Decimal when possible, which favors "user-friendliness" of results | |
over speed of computation. | |
""" | |
from __future__ import division, print_function | |
try: | |
input = raw_input | |
except NameError: | |
pass | |
from math import * | |
import decimal | |
from decimal import Decimal | |
from functools import partial | |
import sys | |
import re | |
import traceback | |
import readline | |
num_regex = re.compile(r'\b[0-9.,]+(?: [0-9.,]+)*\b') | |
replacements = [ | |
# (re.compile(r'(?<=[\d\s\)])x(?=[\s\d\(])'), '*'), # Multiplication as 'a x b' | |
# (re.compile(r'\^'), '**'), # Power as 'a^b' | |
] | |
def normalize_number(number: str): | |
separators = re.sub(r'\d', '', number, flags=re.U) | |
for sep in separators[:-1]: | |
number = number.replace(sep, '') | |
if separators: | |
sep = separators[-1] | |
number = number.replace(sep, '.' if sep!=' ' else '') | |
return number | |
def preprocess_number(match: re.Match, use_decimal): | |
number: str = match.group() | |
number = normalize_number(number) | |
if use_decimal: | |
decimal_number_str = f'Decimal("{number}")' | |
return decimal_number_str | |
else: | |
return number | |
def compute_expression(expr, use_decimal): | |
expr = re.sub(num_regex, partial(preprocess_number, use_decimal=use_decimal), expr) | |
for regex, repl in replacements: | |
expr = re.sub(regex, repl, expr) | |
print(eval(expr)) | |
def enter_calc_prompt(): | |
decimal_context = decimal.getcontext() | |
decimal_context.rounding = decimal.ROUND_HALF_UP | |
while True: | |
try: | |
expr = input("> ") | |
if expr in ["q", "quit", "exit"]: | |
break | |
if not expr: | |
continue | |
try: | |
compute_expression(expr, use_decimal=True) | |
except TypeError: | |
compute_expression(expr, use_decimal=False) | |
except (EOFError, SystemExit): | |
print() | |
break | |
except: | |
traceback.print_exc() | |
if __name__ == "__main__": | |
if len(sys.argv) == 1: | |
enter_calc_prompt() | |
else: | |
compute_expression(' '.join(sys.argv[1:])) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment