Home > OS >  How to get 1 if there is nothing before the 'x' in an equation?
How to get 1 if there is nothing before the 'x' in an equation?

Time:04-16

I am writing some code to calculate the x using the abc-formula in python. It works almost except for one thing. I will first show you my code so you will bettter understand what I mean.

from fractions import Fraction
import math
import re
equation = input("eqation in the form and notation ax2   bx   c = 0: ")
a = list(map(int, re.findall(r'(?<!x)-?\d ', equation.split('=', 1)[0].replace(' ', ''))))[0]
b = list(map(int, re.findall(r'(?<!x)-?\d ', equation.split('=', 1)[0].replace(' ', ''))))[1]
c = list(map(int, re.findall(r'(?<!x)-?\d ', equation.split('=', 1)[0].replace(' ', ''))))[2]
d = b**2-4*a*c
x1 = (-b math.sqrt(d))/(2*a) 
x2 = (-b-math.sqrt(d))/(2*a) 
if x1 == x2: 
    if x1 > 1: 
        answer1 = x1 - math.trunc(x1) 
        print("X1 =",math.trunc(x1),Fraction(answer1).limit_denominator()) 
    else: 
        print("X1 =",Fraction(x1).limit_denominator())
else: 
    if x2 and x1 > 1: 
        answer1 = x1 - math.trunc(x1) 
        answer2 = x2 - math.trunc(x2) 
        if x1.is_integer() and x2.is_integer() == True: 
            print("X1 =",math.trunc(x1), "v", "X2 =",math.trunc(x2)), 
        elif x1.is_integer() == True: 
             print("X1 =",math.trunc(x1), "v", "X2 =", math.trunc(x2),Fraction(answer2).limit_denominator())
        elif x2.is_integer() == True:
             print("X1 =",math.trunc(x1),Fraction(answer1).limit_denominator(), 
            "∨", "X2 =",math.trunc(x2)) 
        else: 
            print("X1 =",math.trunc(x1),Fraction(answer1).limit_denominator(), 
            "∨", "X2 =", math.trunc(x2),Fraction(answer2).limit_denominator())
    elif x1 > 1: 
        answer1 = x1 - math.trunc(x1) 
        print("X1 =",math.trunc(x1),Fraction(answer1).limit_denominator(), "∨", "X2 =", 
        Fraction(x2).limit_denominator()) 
    elif x2 > 1:
        answer2 = x2 - math.trunc(x2) 
        print("X1 =",Fraction(x1).limit_denominator(), "∨", "X2 =", 
        "X2 =", math.trunc(x2),Fraction(answer2).limit_denominator()) 
    else:
        print("X1 =",Fraction(x1).limit_denominator(), "∨", "X2 =",Fraction(x2).limit_denominator())

The important part for my question is just this (but maybe you need the rest for the context):

import re
equation = input("eqation in the form and notation ax2   bx   c = 0: ")
a = list(map(int, re.findall(r'(?<!x)-?\d ', equation.split('=', 1)[0].replace(' ', ''))))[0]
b = list(map(int, re.findall(r'(?<!x)-?\d ', equation.split('=', 1)[0].replace(' ', ''))))[1]
c = list(map(int, re.findall(r'(?<!x)-?\d ', equation.split('=', 1)[0].replace(' ', ''))))[2]

When I run my code and my input is x2 5x - 6 = 0, I get an error:

File "e:\Python\equation.py", line 7, in <module>
    c = list(map(int, re.findall(r'(?<!x)-?\d ', equation.split('=', 1)[0].replace(' ', ''))))[2]
IndexError: list index out of range

I understand why I get an error, because if I look at my input, there is nothing before the x2, so it can't be in the list, so instead of three items in the list there are only two. That's why my c is out of range in my list.

What must I change in order to make the variable a or b, 1 or -1, if there is nothing before the x**2 or x?

CodePudding user response:

One way you could do it is to add 1's before the x's

Add this line right after the equation read

equation = re.sub('(\ |-|^)x', r'\g<1>1x', equation.replace(' ', ''))

This line looks for single x or -x and replaces them with 1x or -1x

CodePudding user response:

You are running the findall function 3 times so you can gain in efficiency with

z = list(map(int, re.findall(r'(?<!x)-?\d ', equation.split('=', 1)[0].replace(' ', ''))))
if z:
   a=z[0]
if z[1]:
  b=z[1]
if z[2]:
  c=z[2]

If you want to put default values use else.
For example

if z[2]:
  c=z[2]
else:
  c=0

CodePudding user response:

TL;DR

This works

a, b, c = map(
    lambda coeff: int(coeff) if coeff else 1,
    re.match(
        r"(-?\d*)x2\s*\ \s*(-?\d*)x\s*\ \s*(-?\d*)\s*=\s*0\s*$",
        input("...")
    ).groups()
)

and will raise an error in case the input is ill-formed.

Explanation

You probably want to match the whole string at once, with the following regex.

equation_pattern = re.compile(r"(?P<a>-?\d*)x2\s*\ \s*(?P<b>-?\d*)x\s*\ \s*(?P<c>-?\d*)\s*=\s*0\s*$")
equation_string = input("...")
match_result = equation_pattern.match(equation_string)
a, b, c = map(lambda coeff: int(coeff) if coeff else 1, match_result.groups())

I have split the code in several lines, and named the capturing groups to make it easier to process step by step what it does.

The idea is that you don't want to find each coefficient individually, but instead you want to match the whole input at once, and use regex to interpret it correctly. Also, this code will only work if the input is of the wanted form. You can check out if the input was correct with match_result, which is None if the result is ill-written.

Naming capturing groups is also useless in this code, I just added that so you could understand where it takes each coefficient, but in your actual code you can just remove that part (or keep it to be able to read it again!), as I did in the TL;DR section.

About using regex to parse an input

Also, this does not work if the input is of the form 2x2-5x 3=0, because it's not what you specified. It will work if it's of the form 2x2 -5x 3=0.

Finally, this is a real simple example so regex keep working, but if you need semantic actions / reduction over the input (that is, you want to understand what the input means, not just check it actually means something), regex are not the most appropriate tool. There is an awkward situation in input recognition where your input is so simple that a full-featured parsing library would be overkill, and yet writing it by hand would be tedious, so you fall back on regex, but writing a regex that covers all the possible inputs in a correct way, producing an easy-to-deal-with Match object is actually quite hard (and often almost impossible to debug once written).

  • Related