Created
October 5, 2020 02:22
-
-
Save paultopia/16e69f9f72ad0a5000fa5b4575ddeee2 to your computer and use it in GitHub Desktop.
Do string-based math with pythonista. mostly because I don't want to buy a fancy string calculator app when I already have python available.
This file contains hidden or 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
# for the pythonista ios app (which comes with sympy bundled) | |
# allows one to create a text file, for example in drafts, containing the string | |
# x - (9 * 5) = x / 2 | |
# and then share it into this pythonista script (or copy it to clipboard and run the script) | |
# and get the answer (90) back. | |
# see comments at end for more examples of stuff that it can solve. | |
# | |
# I wrote this because it annoys me that there are paid apps that do ticker tape calculator kinds of | |
# things. Why should I pay extra to add up a list of numbers whilst still getting to see the numbers when | |
# I have a whole programming language available to me! | |
# | |
# SPECIAL BONUS FUNCTIONALITY: | |
# if you pass it a multiline string containing only numbers | |
# it assumes you just want to sum the lines, then does so. | |
# | |
# caveats: | |
# 1. it may run slow the first time because sympy is a big import; see the in-pythonista docs for sympy. | |
# 2. no error handling at all, no edge cases tested, this is a quick/dirty lazy thing. | |
# | |
# OPTION: I find it annoying to get fractions and things out of this script, so I've included a flag right | |
# at the beginning (SIMPLE_OUTPUT) to get simple python ints and floats out. This will convert | |
# fractions to floats and probably blow up with irrationals and stuff (no clue what it'll do with | |
# irrationals, actually. thisis for stuff like adding up your monthly expenses, not for taking square | |
# roots!). Set it to false to just get the raw sympy output. | |
SIMPLE_OUTPUT = True | |
from sympy.parsing.sympy_parser import parse_expr | |
from sympy.core.numbers import Number, Integer | |
from sympy import solve, Eq | |
import clipboard, appex | |
input = appex.get_text() | |
text = input if input else clipboard.get() | |
# bonus functionality | |
def convert_to_num(s): | |
s = s.strip() | |
try: | |
return int(s) | |
except: | |
try: | |
return float(s) | |
except: | |
return None | |
def check_if_simple_sum(s): | |
s = s.strip() | |
if '\n' in s: | |
lines = s.split() | |
try: | |
return sum([convert_to_num(x) for x in lines]) | |
except: | |
return False | |
return False | |
# core functionality | |
def smush_multiline(s): | |
if '\n' in s: | |
return ''.join(s.split()).strip() | |
else: | |
return s | |
def convert_to_python_number(res): | |
if not SIMPLE_OUTPUT: | |
return res | |
if isinstance(res, Integer): | |
return int(res) | |
return float(res) | |
def extract_python_solutions(res): | |
if len(res) == 1: | |
return convert_to_python_number(res[0]) | |
else: | |
return list(res) | |
def solve_single_string(s): | |
result = parse_expr(s) | |
if isinstance(result, Number): | |
return convert_to_python_number(result) | |
else: | |
return extract_python_solutions(solve(result)) | |
def mathit(s): | |
simple_sum = check_if_simple_sum(s) | |
if simple_sum: | |
return simple_sum | |
s = smush_multiline(s) | |
if '=' in s: | |
terms = [x.strip() for x in s.split("=")] | |
equation = Eq(parse_expr(terms[0]), parse_expr(terms[1])) | |
return extract_python_solutions(solve(equation)) | |
else: | |
return solve_single_string(s) | |
print(mathit(text)) | |
# examples/tests | |
#simple = "3 + 5" | |
#eqzero = "x - 3" | |
#equation = "x + 3 = 5" | |
#twosided = 'x - (9 * 5) = x / 2' | |
#multiline = ''' 10 + | |
#20 | |
#-5 | |
#''' | |
#parens = 'x * (2 + 3) = 20' | |
#noparens = 'x * 2 + 3 = 20' | |
#simplesum = '''5 | |
#10.2 | |
#15 | |
#''' | |
#print(mathit(simple)) # 8 (simple math) | |
#print(mathit(eqzero)) # 3 (solves for x, assuming by default that the other side of equation is 0) | |
#print(mathit(equation)) # 2 (solves for x with specified sided of equation) | |
#print(mathit(twosided)) # 90 (variable on both sides works) | |
#print(mathit(multiline)) # 25 (parses multiline input by concatenating the lines) | |
#print(mathit(parens)) # 4 (not 8.5, i.e., parens for associativity works) | |
#print(mathit(noparens)) # 8.5 (see previous; returns 17/2 if SIMPLE_OUTPUT is False) | |
#print(mathit(simplesum)) # 30.2 (just sum multiline strings when there are no operators or variables) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment