Fetch and validate date by reading char by char in python [closed] - python

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
How do I read a date in MM-DD-YY format and validate as a real date?
I know it would be easier and more robust to handle it with the datetime module - but that's not what I want, so any solutions around using the the following code is appreciated:
dataType = MM-DD-YY
actualResult = 12-31-13
rIndex: counter variable for actualResult
rLen: length of actualResult
def compareDate (dataType, actualResult, rIndex, rLen):
dateString = ""
bhCount , result , count = 0 , 0 , 0
while (rIndex < rLen):
ch = actualResult[rIndex]
print ("Char %c" % ch)
dateString += str(ch)
if(ch >='0' and ch <= '9'):
count += 1
if(count == 2):
count = 0
bHyphen = False
elif(count > 2):
result = -1
break
elif(ch == "-"):
bhCount += 1
if((count == 0) and (bHyphen == False)):
bHyphen = True
else:
break
else:
break
rIndex += 1
#print dateString
return (result, rIndex)
What I am doing wrong? Any help will be appreciated.

class ValidationError(BaseException):
pass
class MyDate(object):
mounth = int()
day = int()
year = int()
_correct_mounth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
def validate(self, day, mounth, year):
if not 1 <= mounth <= 12:
raise ValidationError, 'Invalid mounth!'
if year < 1:
raise ValidationError, 'Invalid year!'
if mounth == 2 and not year % 4:
if not 1 <= day <= 29:
raise ValidationError, 'Invalid day!'
else:
if not 1 <= day <= self._correct_mounth[mounth-1]:
raise ValidationError, 'Invalid day!'
return True
def __init__(self, date):
if not isinstance(date, basestring):
raise ValidationError, 'Not a string!'
date_parts = date.split('-')
if not isinstance(date_parts, list) or not len(date_parts) == 3:
raise ValidationError, 'Can`t change to list with 3 elements!'
for i in date_parts:
try:
int(i)
except TypeError:
raise ValidationError, 'Cannot convert to int!'
mounth = int(date_parts[0])
day = int(date_parts[1])
year = int(date_parts[2])
if self.validate(day, mounth, year):
self.mounth, self.day, self.year = mounth, day, year
dates = '12-31-13|08-23-12|10-10-13'
unchecked_dates = dates.split('|')
checked_dates = list()
for d in unchecked_dates:
try:
new_date = MyDate(d)
except ValidationError, e:
print '{0} is invalid date! {1}'.format(d, e)
else:
checked_dates.append(new_date)
if len(unchecked_dates) == len(checked_dates):
print 'All dates are correct.'
else:
print 'Correct dates: {0}'.format(checked_dates)

ANSWER
def compareDate (dataType, actualResult, rIndex, rLen):
hyphenCount , result , count = 0 , 0 , 0
dateString = ""
while (rIndex < rLen):
ch = actualResult[rIndex]
if (ch == '.'):
break
if(ch >= '0' and ch <= '9'):
hyphenCount = 0
count += 1
if(count > 2):
result = -1
print " d = "
break;
dateString += str(ch)
if(ch == '-'):
count = 0
hyphenCount += 1
if(hyphenCount > 1):
print " h = "
result = -1
break
#print ("Char %c" % ch)
rIndex += 1
print "dateString is = %s" % dateString
if result != -1:
msg = ""
mt = dateString[0] + dateString[1]
dt = dateString[2] + dateString[3]
yr = dateString[4] + dateString[5]
leap = '20'+yr
print mt, dt, yr
mt = int(mt)
dt = int(dt)
yr = int (yr)
leap = int(yr)
#create and call function which verify date
result,msg = verifyDate(mt,dt,yr,leap)
print msg
return (result, rIndex)
def verifyDate(mt,dt,yr,leap):
res = 0
msg = ""
leapyr = checkForLeapYear(leap)
if(yr >= 00 and yr <= 99):
if(leapyr): # for leap year
if(mt == 2):
if(dt >= 01 and dt <= 29):
res = 0
else:
msg = "should not exceed 29"
elif(mt == 1 or mt == 3 or mt == 5 or mt == 7 or mt == 8 or mt == 10 or mt == 12):
if(dt >= 01 and dt <= 31):
res = 0
else:
msg = "should not exceed 31"
res = -1
elif(mt == 4 or mt == 6 or mt == 9 or mt == 11):
if(dt >= 01 and dt <= 30):
res = 0
else:
msg = "should not exceed 30"
res = -1
else:
msg = "month should in btwn 01 to 12"
res = -1
# for leap year ...Ends Here
else:
if((mt >= 1) and (mt <= 12)):
if(mt == 2):
if(dt >= 01 and dt <= 28):
res = 0
else:
msg = "should not exceed 28"
res = -1
elif(mt == 1 or mt == 3 or mt == 5 or mt == 7 or mt == 8 or mt == 10 or mt == 12):
if(dt >= 01 and dt <= 31):
res = 0
else:
msg = "should not exceed 31"
res = -1
elif(mt == 4 or mt == 6 or mt == 9 or mt == 11):
if(dt >= 01 and dt <= 30):
res = 0
else:
msg = "should not exceed 30"
res = -1
else:
msg = "month should in btwn 01 to 12"
res = -1
else:
msg = "year should in btwn 00 to 99"
res = -1
return (res,msg)
def checkForLeapYear(yr):
if((yr %100) == 0 and (yr % 400 == 0 )):
return True
elif(yr%4 == 0):
return True
else:
return False
What else i can do with code to improve complexity and reduce lines of code.
Please answer with examples..

Related

count the number of days between two dates

I am counting number of days between two dates.For first testcase output is wrong 10108
expected output 10109
In first test case 1 day is missing in output
from typing import*
class Solution:
def daysBetweenDates(self, date1: str, date2: str) -> int:
d1 = self.days(int(date1[:4]),int(date1[5:7]),int(date1[8:]))
d2 = self.days(int(date2[:4]),int(date2[5:7]),int(date2[8:]))
return abs(d2-d1)
def isLeap (self, N):
if N % 400 == 0:
return True
if N % 100 == 0:
return False
if N % 4 != 0:
return False
return True
def days(self, year,month,rem_days):
months_list = [31,28,31,30,31,30,31,31,30,31,30,31]
days_count = 0
for i in range(1971,2101):
if year > i:
if self.isLeap(i):
days_count += 366
else:
days_count += 365
else:
break
if self.isLeap(year) and month > 2:
days_count += 1
for j in range(1,month):
if month > j:
days_count += months_list[j]
return days_count + rem_days
vals = Solution()
print(vals.daysBetweenDates("2010-09-12","1983-01-08"))
print(vals.daysBetweenDates("2019-06-29", "2019-06-30"))
print(vals.daysBetweenDates("2020-01-15", "2019-12-31"))
The month starts at one, you get the number of days for each month from the wrong index (1 for January when the correct index is 0...). Subtract one when you look up the days for each month
for j in range(1, month):
days_count += months_list[j - 1]

delete 0 value in list

hello I try to make an app- personality test, but i have a problem with evaluation,..
there is a dificult evaluation of test but in short in theese reduce version you just write some values into a given variable, and i want to delete every 0 value from list as a result.. I tried it (programe after # but there is an error), could anybody please help me?
error
File "C:/Users/Stanko/PycharmProjects/pythonProjectDISK/main.py", line 73, in dele
self._data[self.item.key]= list(filter(lambda num: num != 0, self._data[self.item.key]))
AttributeError: 'Test' object has no attribute 'item'
here is a reduce program
class Empty(Exception):
pass
class PriorityVal(ABC):
class _Item:
def __init__(self, key, value):
self.key, self.value = key, value
def __lt__(self, other):
return self.key < other.key
def __repr__(self):
return str((self.key, self.value))
#abstractmethod
def add(self, key, value):
pass
#abstractmethod
def max(self):
pass
#abstractmethod
def min(self):
pass
#abstractmethod
def remove_min(self):
pass
class Test(PriorityVal):
def __init__(self):
self._data = []
def add(self, key, value):
self._data.append(self._Item(key, value))
def max(self):
index = self.find_max()
item = self._data[index]
return item.key, item.value
def find_max(self):
index = 0
for i in range(1, len(self._data)):
if self._data[index] < self._data[i]:
index = i
return index
def _find_min(self):
index = 0
for i in range(1, len(self._data)):
if self._data[i] < self._data[index]:
index = i
return index
def min(self):
index = self._find_min()
item = self._data[index]
return item.key, item.value
def remove_min(self):
index = self._find_min()
item = self._data.pop(index)
return item.key, item.value
def dele(self):
self._data[self.item.key]= list(filter(lambda num: num != 0, self._data[self.item.key]))
test = str(input("test name"))
test = Test()
dzadane = int(input("input d"))
if dzadane <= 0:
dh = 0
elif 0 < dzadane <= 4:
dh = 60
elif 4 < dzadane <= 7:
dh = 70
elif 7 < dzadane <= 12:
dh = 80
elif 12 < dzadane <= 15:
dh = 90
else:
dh = 100
test.add(dh, "d")
izadane = int(input("input i"))
if izadane <= -1:
ih = 0
elif -1 < izadane <= 1:
ih = 60
elif 1 < izadane <= 3:
ih = 70
elif izadane == 4:
ih = 75
elif 4 < izadane <= 6:
ih = 80
elif izadane == 7:
ih = 85
elif 7 < izadane <= 9:
ih = 90
else:
dh = 100
test.add(ih, "i")
szadane = int(input("input s"))
if szadane <= -2:
sh = 0
elif -2 < szadane <= 0:
sh = 60
elif 0 < szadane <= 3:
sh = 70
elif 4 < szadane <= 7:
sh = 80
elif szadane == 8:
sh = 85
elif 8 < szadane <= 10:
sh = 90
else:
sh = 100
test.add(sh, "s")
kzadane = int(input("input k"))
if kzadane <= -3:
kh = 0
elif -3 < kzadane <= 1:
kh = 60
elif -1 < kzadane <= 1:
kh = 70
elif 1 < kzadane <= 4:
kh = 80
elif 4 < kzadane <= 7:
kh = 90
else:
kh = 100
test.add(kh, "k")
nzadane = int(input("input n"))
nh = 0
test.add(nh, "n")
print(dzadane, izadane, szadane, kzadane, nzadane, )
print("test", test._data)
print('max=', test.max())
print( "del all 0", test.dele())
print("test", test._data)
You could try
self._data = [value for value in self._data if value.key != 0]

UnboundLocalError: local variable 'msg' referenced before assignment. How to fix it?

I'm getting count of messages from json file, but i have an error... And i do not know why. In this program bot has to send information about member in mention. If I write msg = None at the beginning of the code, it won't send like > messages = 10 it will send messages = None
PROGRAM
if args[0] == '!in':
await client.delete_message(message)
highclass = None
gm = ""
clan = None
if (roleLeaders in message.author.roles or roleHunter in message.author.roles or roleDeputy in message.author.roles):
for member in message.mentions:
user = member
userjoin = str(user.joined_at)
joinpars= userjoin.split()
join = joinpars[0]
msg1 = user_get_msg(member.id)
time1 = user_get_time(member.id)
s = str(msg1)
last = int(s[-1])
st = str(time1)
stm = time1 // 60
sth = stm // 60
std = sth // 24
if time1 <= 60:
lastt = int(st[-1])
if lastt == 0:
time = '{0} секунд'.format(time1)
if lastt == 1 and not time1 == 11:
time = '{0} секунду'.format(time1)
if ((time1 >= 11 and time1 <= 19) or (lastt >= 5 and lastt <= 9)):
time = '{0} секунд'.format(time1)
if (lastt >= 2 and lastt <= 4) and not (time1 >= 11 and time1 <= 19):
time = '{0} секунды'.format(time1)
if time1 <= 3600 and time1 > 60:
lastt = int(str(stm)[-1])
if lastt == 0:
time = '{0} минут'.format(stm)
if lastt == 1 and not stm == 11:
time = '{0} минуту'.format(stm)
if ((stm >= 11 and stm <= 19) or (lastt >= 5 and lastt <= 9)):
time = '{0} минут'.format(stm)
if (lastt >= 2 and lastt <= 4) and not (stm >= 11 and stm <= 19):
time = '{0} минуты'.format(stm)
if time1 <= 86400 and time1 >3600:
lastt = int(str(sth)[-1])
if lastt == 0:
time = '{0} часов'.format(sth)
if lastt == 1 and not sth == 11:
time = '{0} час'.format(sth)
if ((sth >= 11 and sth <= 19) or (lastt >= 5 and lastt <= 9)):
time = '{0} часов'.format(sth)
if (lastt >= 2 and lastt <= 4) and not (sth >= 11 and sth <= 19):
time = '{0} часа'.format(sth)
if time1 >= 86400:
lastt = int(str(std)[-1])
if lastt == 0:
time = '{0} дней'.format(std)
if lastt == 1 and not std == 11:
time = '{0} день'.format(std)
if ((std >= 11 and std <= 19) or (lastt >= 5 and lastt <= 9)):
time = '{0} дней'.format(std)
if (lastt >= 2 and lastt <= 4) and not (std >= 11 and std <= 19):
time = '{0} дня'.format(std)
if msg1 >= 0:
if last == 0 or msg1 == 0:
msg = '{0} записок'.format(msg1)
if msg1 == 1 or (last == 1 and msg1 >= 21):
msg = '{0} записку'.format(msg1)
if (msg1 >= 2 and msg1 <= 4) or (msg1 >= 22 and msg1 <= 24):
msg = '{0} записки'.format(msg1)
if (last >= 5 and last <= 9):
msg = '{0} записок'.format(msg1)
for role in member.roles:
with open('class.json', 'r') as roleread:
if role.id in roleread.read():
highclass = '<#&{0}>'.format(role.id)
with open('clans.json', 'r') as fp:
if role.id in fp.read():
gm = '> Является участником гильдии <#&{0}>.'.format(role.id)
if roleGM in member.roles:
gm = '> Является **мастером** гильдии <#&{0}>.'.format(role.id)
await asyncio.sleep(0.01)
await client.send_message(message.channel, 'Персонаж {0}:\n'
'> Прибыл в город **{1}**;\n'
'> Принимал участие в жизни города **{2}**;\n'
'> Написал **{3}**;\n'
'> Имеет класс {4};\n'
'{5}'.format(member.mention, join, time, msg, highclass, gm))
ERROR
File "soul.py", line 497, in on_message
'{5}'.format(member.mention, join, time, msg, highclass, gm))
UnboundLocalError: local variable 'msg' referenced before assignment
I've tried everything, what I could. Can somebody help me?
Look at how you assign a value to msg:
if last == 0 or msg1 == 0:
msg = '{0} some useless tex'.format(msg1)
if msg1 == 1 or (last == 1 and msg1 >= 21):
msg = '{0} some useless tex'.format(msg1)
if (msg1 >= 2 and msg1 <= 4) or (msg1 >= 22 and msg1 <= 24):
msg = '{0} some useless tex'.format(msg1)
if (last >= 5 and last <= 9):
msg = '{0} some useless tex'.format(msg1)
So, what happens if, say, msg1 is some value in the range 10-20 (and last is not 0)? Then none of these ifs will trigger. So msg will never get assigned anything. But you'll try to use it anyway, and get that error.
You probably want something like this:
if last == 0 or msg1 == 0:
msg = '{0} some useless tex'.format(msg1)
elif msg1 == 1 or (last == 1 and msg1 >= 21):
msg = '{0} some useless tex'.format(msg1)
elif (msg1 >= 2 and msg1 <= 4) or (msg1 >= 22 and msg1 <= 24):
msg = '{0} some useless tex'.format(msg1)
elif (last >= 5 and last <= 9):
msg = '{0} some useless tex'.format(msg1)
else:
msg = '{0} WARNING! UNEXPECTED VALUE!'.format(msg1)
(Notice that changing all those ifs to elifs could be a semantically meaningful change. If two conditions could both be true, your original code would execute both of them, so the second one would override what the first did, but the new code will only execute the first one. If it makes a difference, this is actually more often what you want—but if you wanted the other behavior, you may need to rewrite or reorder your conditions.)

Need help in adding binary numbers in python

If I have 2 numbers in binary form as a string, and I want to add them I will do it digit by digit, from the right most end. So 001 + 010 = 011
But suppose I have to do 001+001, how should I create a code to figure out how to take carry over responses?
bin and int are very useful here:
a = '001'
b = '011'
c = bin(int(a,2) + int(b,2))
# 0b100
int allows you to specify what base the first argument is in when converting from a string (in this case two), and bin converts a number back to a binary string.
This accepts an arbitrary number or arguments:
>>> def bin_add(*bin_nums: str) -> str:
... return bin(sum(int(x, 2) for x in bin_nums))[2:]
...
>>> x = bin_add('1', '10', '100')
>>> x
'111'
>>> int(x, base = 2)
7
Here's an easy to understand version
def binAdd(s1, s2):
if not s1 or not s2:
return ''
maxlen = max(len(s1), len(s2))
s1 = s1.zfill(maxlen)
s2 = s2.zfill(maxlen)
result = ''
carry = 0
i = maxlen - 1
while(i >= 0):
s = int(s1[i]) + int(s2[i])
if s == 2: #1+1
if carry == 0:
carry = 1
result = "%s%s" % (result, '0')
else:
result = "%s%s" % (result, '1')
elif s == 1: # 1+0
if carry == 1:
result = "%s%s" % (result, '0')
else:
result = "%s%s" % (result, '1')
else: # 0+0
if carry == 1:
result = "%s%s" % (result, '1')
carry = 0
else:
result = "%s%s" % (result, '0')
i = i - 1;
if carry>0:
result = "%s%s" % (result, '1')
return result[::-1]
Can be simple if you parse the strings by int (shown in the other answer). Here is a kindergarten-school-math way:
>>> def add(x,y):
maxlen = max(len(x), len(y))
#Normalize lengths
x = x.zfill(maxlen)
y = y.zfill(maxlen)
result = ''
carry = 0
for i in range(maxlen-1, -1, -1):
r = carry
r += 1 if x[i] == '1' else 0
r += 1 if y[i] == '1' else 0
# r can be 0,1,2,3 (carry + x[i] + y[i])
# and among these, for r==1 and r==3 you will have result bit = 1
# for r==2 and r==3 you will have carry = 1
result = ('1' if r % 2 == 1 else '0') + result
carry = 0 if r < 2 else 1
if carry !=0 : result = '1' + result
return result.zfill(maxlen)
>>> add('1','111')
'1000'
>>> add('111','111')
'1110'
>>> add('111','1000')
'1111'
It works both ways
# as strings
a = "0b001"
b = "0b010"
c = bin(int(a, 2) + int(b, 2))
# as binary numbers
a = 0b001
b = 0b010
c = bin(a + b)
you can use this function I did:
def addBinary(self, a, b):
"""
:type a: str
:type b: str
:rtype: str
"""
#a = int('10110', 2) #(0*2** 0)+(1*2**1)+(1*2**2)+(0*2**3)+(1*2**4) = 22
#b = int('1011', 2) #(1*2** 0)+(1*2**1)+(0*2**2)+(1*2**3) = 11
sum = int(a, 2) + int(b, 2)
if sum == 0: return "0"
out = []
while sum > 0:
res = int(sum) % 2
out.insert(0, str(res))
sum = sum/2
return ''.join(out)
def addBinary(self, A, B):
min_len, res, carry, i, j = min(len(A), len(B)), '', 0, len(A) - 1, len(B) - 1
while i>=0 and j>=0:
r = carry
r += 1 if A[i] == '1' else 0
r += 1 if B[j] == '1' else 0
res = ('1' if r % 2 == 1 else '0') + res
carry = 0 if r < 2 else 1
i -= 1
j -= 1
while i>=0:
r = carry
r += 1 if A[i] == '1' else 0
res = ('1' if r % 2 == 1 else '0') + res
carry = 0 if r < 2 else 1
i -= 1
while j>=0:
r = carry
r += 1 if B[j] == '1' else 0
res = ('1' if r % 2 == 1 else '0') + res
carry = 0 if r < 2 else 1
j -= 1
if carry == 1:
return '1' + res
return res
#addition of two binary string without using 'bin' inbuilt function
numb1 = input('enter the 1st binary number')
numb2 = input("enter the 2nd binary number")
list1 = []
carry = '0'
maxlen = max(len(numb1), len(numb2))
x = numb1.zfill(maxlen)
y = numb2.zfill(maxlen)
for j in range(maxlen-1,-1,-1):
d1 = x[j]
d2 = y[j]
if d1 == '0' and d2 =='0' and carry =='0':
list1.append('0')
carry = '0'
elif d1 == '1' and d2 =='1' and carry =='1':
list1.append('1')
carry = '1'
elif (d1 == '1' and d2 =='0' and carry =='0') or (d1 == '0' and d2 =='1' and
carry =='0') or (d1 == '0' and d2 =='0' and carry =='1'):
list1.append('1')
carry = '0'
elif d1 == '1' and d2 =='1' and carry =='0':
list1.append('0')
carry = '1'
else:
list1.append('0')
if carry == '1':
list1.append('1')
addition = ''.join(list1[::-1])
print(addition)
Not an optimal solution but a working one without use of any inbuilt functions.
# two approaches
# first - binary to decimal conversion, add and then decimal to binary conversion
# second - binary addition normally
# binary addition - optimal approach
# rules
# 1 + 0 = 1
# 1 + 1 = 0 (carry - 1)
# 1 + 1 + 1(carry) = 1 (carry -1)
aa = a
bb = b
len_a = len(aa)
len_b = len(bb)
min_len = min(len_a, len_b)
carry = 0
arr = []
while min_len > 0:
last_digit_aa = int(aa[len(aa)-1])
last_digit_bb = int(bb[len(bb)-1])
add_digits = last_digit_aa + last_digit_bb + carry
carry = 0
if add_digits == 2:
add_digits = 0
carry = 1
if add_digits == 3:
add_digits = 1
carry = 1
arr.append(add_digits) # will rev this at the very end for output
aa = aa[:-1]
bb = bb[:-1]
min_len -= 1
a_len_after = len(aa)
b_len_after = len(bb)
if a_len_after > 0:
while a_len_after > 0:
while carry == 1:
if len(aa) > 0:
sum_digit = int(aa[len(aa) - 1]) + carry
if sum_digit == 2:
sum_digit = 0
carry = 1
arr.append(sum_digit)
aa = aa[:-1]
else:
carry = 0
arr.append(sum_digit)
aa = aa[:-1]
else:
arr.append(carry)
carry = 0
if carry == 0 and len(aa) > 0:
arr.append(aa[len(aa) - 1])
aa = aa[:-1]
a_len_after -= 1
if b_len_after > 0:
while b_len_after > 0:
while carry == 1:
if len(bb) > 0:
sum_digit = int(bb[len(bb) - 1]) + carry
if sum_digit == 2:
sum_digit = 0
carry = 1
arr.append(sum_digit)
bb = bb[:-1]
else:
carry = 0
arr.append(sum_digit)
bb = bb[:-1]
else:
arr.append(carry)
carry = 0
if carry == 0 and len(bb) > 0:
arr.append(bb[len(bb) - 1])
bb = bb[:-1]
b_len_after -= 1
if carry == 1:
arr.append(carry)
out_arr = reversed(arr)
out_str = "".join(str(x) for x in out_arr)
return out_str

Calculator which parses user input

import string
# Strength of operations:
# -> [] (brackets)
# 6 -> ~ (negative)
# 5 -> #, $, & (average, maximum, minimum)
# 4 -> %, ! (modulo, factorial)
# 3 -> ^ (power)
# 2 -> *, / (multiplication, division)
# 1 -> +, - (addition, subtraction)
def BinaryOperation(exp, idx):
""" Gets an expression and an index of an operator and returns a tuple with (first_value, operator, second_value). """
first_value = 0
second_value = 0
#Get first value
idx2 = idx -1
if idx2 == 0:
first_value = exp[idx2:idx]
else:
while (idx2 > 0) and (exp[idx2] in string.digits):
idx2 -=1
if (exp[idx2] in ("-")) or (exp[idx2] in string.digits):#-5*3
first_value = exp[idx2:idx]
else:#%5*3
first_value = exp[idx2+1:idx]
#Get second value
idx2 = idx +1
if exp[idx+1] not in string.digits: #If there is something like 1*+5, second_sign will be +.
idx2 += 1 #idx2 will begin from the char after the sign.
while (idx2 < len(exp)) and (exp[idx2] in string.digits):
idx2 += 1
second_value = exp[idx+1:idx2]
return (first_value, exp[idx], second_value)
def UnaryOperation(exp, idx):
""" Gets an expression and an index of an operator and returns a tuple with (operator, value). """
#Get value
idx2 = idx+1
if exp[idx+1] not in string.digits: #If there is something like ~-5, second_sign will be -.
idx2 += 1 #idx2 will begin from the char after the sign.
while (idx2 < len(exp)) and (exp[idx2] in string.digits):
idx2 +=1
return (exp[idx], exp[idx+1:idx2])
def Brackets(exp):
idx = 0
while idx < len(exp):
if exp[idx] == "[":
#Brackets
close_bracket = exp.find("]")
if close_bracket == -1:
raise Exception("Missing closing bracket.")
exp_brackets = exp[idx+1:close_bracket]
value = str(solve(exp_brackets))
exp = exp.replace("[" + exp_brackets + "]", value)
idx = 0 #The len has been changed, scan again.
idx += 1
return Level6(exp)
def Level6(exp):
idx = 0
while idx < len(exp):
if exp[idx] in ("~"):
#Negative
sub_exp = UnaryOperation(exp, idx)
value = ~int(sub_exp[1])
value = str(value)
exp = exp.replace(''.join(sub_exp), value)
idx = 0 #The len has been changed, scan again.
idx += 1
return Level5(exp)
def Level5(exp):
idx = 0
while idx < len(exp):
if exp[idx] in ("#", "$", "&"):
#Average, Maximum and Minimum
sub_exp = BinaryOperation(exp, idx)
first_value = int(sub_exp[0])
second_value = int(sub_exp[2])
if sub_exp[1] == "#":
value = (first_value + second_value)/2
if sub_exp[1] == "$":
value = first_value if first_value > second_value else second_value
if sub_exp[1] == "&":
value = first_value if first_value < second_value else second_value
value = str(value)
exp = exp.replace(''.join(sub_exp), value)
idx = 0 #The len has been changed, scan again.
idx += 1
return Level4(exp)
def Level4(exp):
idx = 0
while idx < len(exp):
if exp[idx] in ("%","!"):
#Modulo and Factorial
if exp[idx] == "%":
sub_exp = BinaryOperation(exp, idx)
value = int(sub_exp[0]) % int(sub_exp[2])
if exp[idx] == "!":
sub_exp = UnaryOperation(exp, idx)
value = reduce(lambda x,y:x*y, range(1, int(sub_exp[1])+1))
value = str(value)
exp = exp.replace(''.join(sub_exp), value)
idx = 0 #The len has been changed, scan again.
idx += 1
return Level3(exp)
def Level3(exp):
idx = 0
while idx < len(exp):
if exp[idx] in ("^"):
#Power
sub_exp = BinaryOperation(exp, idx)
value = int(sub_exp[0]) ** int(sub_exp[2])
value = str(value)
exp = exp.replace(''.join(sub_exp), value)
idx = 0 #The len has been changed, scan again.
idx += 1
return Level2(exp)
def Level2(exp):
idx = 0
while idx < len(exp):
if exp[idx] in ("*", "/"):
#Multiplication and Division
sub_exp = BinaryOperation(exp, idx)
if sub_exp[1] == "*":
value = int(sub_exp[0]) * int(sub_exp[2])
if sub_exp[1] == "/":
value = int(sub_exp[0]) / int(sub_exp[2])
value = str(value)
exp = exp.replace(''.join(sub_exp), value)
idx = 0 #The len has been changed, scan again.
idx += 1
return Level1(exp)
def Level1(exp):
idx = 0
while idx < len(exp):
if (exp[idx] in ("+", "-")) and (idx != 0):
#Addition and Subtraction
sub_exp = BinaryOperation(exp, idx)
if sub_exp[1] == "+":
value = int(sub_exp[0]) + int(sub_exp[2])
if sub_exp[1] == "-":
value = int(sub_exp[0]) - int(sub_exp[2])
value = str(value)
exp = exp.replace(''.join(sub_exp), value)
idx = 0 #The len has been changed, scan again.
idx += 1
return exp
def solve(exp):
exp = Brackets(exp)
return float(exp) if "." in exp else int(exp)
def remove_whitespace(exp):
""" Gets a string and removes all whitespaces and tabs """
exp = exp.replace(" ", "")
exp = exp.replace("\t", "")
return exp
while True:
exp = raw_input("")
exp = remove_whitespace(exp)
print solve(exp)
I have written this program after a lot of effort, and I was wondering about the efficiency of that solution and if it's neat.
So my question is, how plain is this program and is there any better way to rewrite it?
just for the point.
>>> eval(raw_input("input calculation: "))
input calculation: 1+1
2
>>> eval(raw_input("input calculation: "))
input calculation: (6*4^2)
26
>>> eval(raw_input("input calculation: "))
input calculation: (3/2.3)*4
5.2173913043478262
for an innocent program, you can use eval
but you really shouldn't use it ever. its only real use is confusing people, and being a fun novelty if you write programs fro yourself and decide you want a calculator.
there are many ways to write a calculator function.
try some of these other answers:
Python creating a calculator
Basic calculator program in python
python calculator program
If you want to check out some custom class-based evaluation engines in Python, these might help you:
Expression Evaluator (version 1 with source)
Math Evaluator (version 2 with source)
again = True
answer = ""
while again is True:
try:
expression = raw_input("Enter your expression: ")
found = False
oper = -1
operator1 = 0
operator2 = 0
while found==False:
if (expression.find("+")>0 and expression.find("+")<len(expression)-1):
found = True
oper = expression.find("+")
operator1 = float(expression[:oper])
operator2 = float(expression[oper+1:])
print "{} + {} = {}".format(operator1,operator2,operator1+operator2)
elif(expression.find("-")>0 and expression.find("-")<len(expression)-1):
found = True
oper = expression.find("-")
operator1 = float(expression[:oper])
operator2 = float(expression[oper+1:])
print "{} - {} = {}".format(operator1,operator2,operator1-operator2)
elif(expression.find("*")>0 and expression.find("*")<len(expression)-1):
found = True
oper = expression.find("*")
operator1 = float(expression[:oper])
operator2 = float(expression[oper+1:])
print "{} * {} = {}".format(operator1,operator2,operator1*operator2)
elif(expression.find("/")>0 and expression.find("/")<len(expression)-1):
found = True
oper = expression.find("/")
operator1 = float(expression[:oper])
operator2 = float(expression[oper+1:])
print "{} / {} = {}".format(operator1,operator2,operator1/operator2)
else:
oper = -1
found = False
print "Incorrect expression, please try again"
break
again = False
answer = raw_input("Try again?: ")
if(answer == "y" or answer=="yes" or answer =="Y" or answer == "YES"):
again = True
else:
again = False
print "Thank you for playing! See you next time."
break
except:
print "Failed, check your expression and try again"

Categories