Quadratic "Complete the Square" Solver in Python 3 I quickly wrote this program to transform quadratic expressions in general form into vertex form.

\$ax^2 + bx + c \;=\; a(x-h)^2 + k,\quad\text{where}\quad h = -\frac{b}{2a} \quad\text{and}\quad k = c - ah^2 = c - \frac{b^2}{4a}.\$

The actual conversion is easy, but with writing a lexer/parser came pain points: 


I tokenize with Regex, and some of the regex patterns are built dynamically using f-strings (which seems suspect).  
I use eval to compute terms in parentheses (to make fractions easy to input, for example).


I also feel like there's probably a library for working with ASCII-fied algebraic expressions, (lots of the same kind of code populates sites like Symbolab, Cymath and Desmos,) but I do not know of it.

## Tests:
# user_in = "(16/4)x^2 7x (3**2)" -&gt; "Result is: 4.0(x + (0.875))^2 + (5.9375)" (Passes)
# user_in = "(41*4)x^2 41x 2" -&gt; "Result is: 164.0(x + (0.125))^2 + (-0.5625)" (Passes)
# user_in = "x^2 4" -&gt; "Result is: (x + (2.0))^2 + (-4.0)" (Fails)
# user_in = "x^2 4x 16" -&gt; "Result is (x + (2.0))^2 + 12.0" (Fails)


import re

print("""~~~Square Completer!~~~
Enter the terms of your quadratic equation in standard form
Addition is implied, terms separated by spaces.
Only use one kind of single-letter variable in the whole expression.
Surround computations such as constant multiplication and fractions in parens.
DO NOT put variables inside parens!""")
user_in = input("&gt; ")

# extract the variable
def extract_variable(expression):
    letters = re.findall(r'[a-z]', expression) # all the letters
    if all(match == letters[0] for match in letters): # if all letters == the first one
        return letters[0] # we have our variable
    else:
        raise ValueError("Only use one kind of single-letter variable in the whole expression.")

variable = extract_variable(user_in)

# eval all things in parens and split string into terms
def split_into_terms(expression):
    expression = re.sub(fr"\([^{variable}\)]+\)", lambda m: str(eval(m.group())), expression)
    print(f"working with {expression}")
    return expression.split(' ')

terms = split_into_terms(user_in)
print(terms)

# sort terms into bins

def bin_terms(terms):
    squareds, x_es, constants = [], [], []
    for term in terms:
        term = term.strip().lower()
        if term.endswith('^2'):
            squareds.append(term[:-2]) # without trailing '^2'
        elif term.endswith(variable):
            x_es.append(term)
        elif bool(re.search(r"^-?[0-9\.]+$", term)): # if the term contains only numbers
            constants.append(term)
    return squareds, x_es, constants

squareds, x_es, constants = bin_terms(terms)

print('unprocessed:', squareds, x_es, constants, sep='\n')


def sum_bins(squareds, x_es, constants):
    squareds = [squared[:-1] for squared in squareds if squared.endswith(variable)] # 2x -&gt; 2
    print('squareds step1:', squareds, sep='\n')
    squareds = ['1' if squared == variable else squared for squared in squareds] # x -&gt; 1
    print('step2:', squareds)

    print('\nprocessed:', squareds, x_es, constants, sep='\n')

    constant = sum(float(c) for c in constants)
    print('\n ***EXES: ', x_es,'***')
    x = sum(float(el[:-1]) for el in x_es)
    print('\n ***SUMX: ', x,'***')
    squared = sum(float(el) for el in squareds)

    return squared, x, constant

squared, x, constant = sum_bins(squareds, x_es, constants)

##print('\ntotals:', squared, x, constant, sep='\n')

##constant = constant / squared
##x = x / squared
##squared = 1

##print('\nover square term:', squared, x, constant, sep='\n')

def complete_square(a,b,c):
    """
    Complete the square, transforming a quadratic
    of form
    ax^2 + bx + c
    to form
    a(x + p)^2 - q
    """
    p = b/(2*a)
    q = c - (b**2)/(4*a)
    return p, q


p, q = complete_square(squared, x, constant)
a = squared
print(f'Result is: {a}({variable} + ({p}))^2 + ({q})')
There is a library to help with this! Check out sympy, particularly sympify and parse_expr.