import re
from math import gcd
from fractions import Fraction

RXP = r"(\s*[\+\-]\s*)?(\d*)(x?)(\d*)"

tests = ["2x2 - 5x + 2", "x2 + x - 6", "x + 5", "12x2 + 4x1 + 0x0"]

def rational_zeros(st):
    poly = {}
    for lst in re.findall(RXP, st):
        if any(x != '' for x in lst):
            a, b, c, d = lst
            sgn = 1 if a == '' or a == ' + ' else -1
            coef = int(b) if b != '' else 1
            deg = 0
            if c == 'x':
                deg = int(d) if d != '' else 1
            poly[deg] = sgn * coef
            
    n = max(poly.keys())
    m = min([k for k in poly.keys() if poly[k] != 0])

    roots = []
    if m > 0:
        roots.extend([(0, 1)] * m)
        poly = {k - m: poly[k] for k in poly.keys()}
        n -= m
    
    an, a0 = map(abs, (poly[n], poly.get(0, 0)))
    
    def derive(fn):
        return {k - 1: k * fn[k] for k in fn if k > 0}
    
    def eval(fn, p, q):
        return sum(fn[k] * p**k * q**(n - k) for k in fn)

    ps = [d for d in range(1, a0 + 1) if a0 % d == 0]
    qs = [d for d in range(1, an + 1) if an % d == 0]
    
    for p in ps:
        for q in qs:
            for sgn in (1, -1):
                if eval(poly, sgn * p, q) == 0:
                    g = gcd(p, q)
                    tu = (sgn * p // g , q // g) 
                    if not tu in roots:                        
                        multiplicity = 0
                        m = dict(poly)
                        while 1:
                            if eval(m, tu[0], tu[1]) != 0:
                                break
                            m = derive(m)
                            multiplicity += 1
                        roots.extend([tu] * multiplicity)
                    
    return sorted([Fraction(x, y) for x, y in roots])

for test in tests:
    p = rational_zeros(test)
    print(p)

Embed on website

To embed this program on your website, copy the following code and paste it into your website's HTML: