Is there better way to change string for evaluation - python-2.7

Is there better way of changing one of numbers to float in division?
I am currently having 1 loop that scan my equation for '/' sign and second that take number after '/' and change it to float. How can I improve it?
#!/usr/bin/env python2.7
import Tkinter as tk
main = tk.Tk()
main.title('Calculator')
def insert_variable(i):
"""Inserts the user defined sign and puts it on the end the entry widget"""
END = len(calc_entry.get())
calc_entry.insert(END,i)
def calculate():
''' deletes all characters in the entry and inserts evaluation of the equation '''
equation = calc_entry.get()
try:
calc_entry.delete(0, len(equation)) # deletes all characters in the entry
for i in range(len(equation)-1):# loop for checking for special signs
if equation[i] == '/': #if there is '/' sign change one of numbers to float
for j in range(i+1,len(equation)): # loop for number of digits after '/' sign
if equation[j] == '.': # if there is dot go ones more
pass
else:
try:
int(equation[j])# if there is something other than digit go to exception
except ValueError:
equation = equation[:i+1] + str(float(equation[i+1:j])) + equation[j:]# change number after / to float and join all strings
break
if equation[i] == '^': # if there is ^ sign change it for '**'
equation = equation[:i] +'**'+ equation[i+1:]
print equation
calc_entry.insert(0, str(round(eval(equation), 3))) # evaluates (calculates) the equation after loop
except SyntaxError:
calc_entry.insert(0,'<ERROR>')
except ZeroDivisionError:
calc_entry.insert(0,'ERROR DIVISION BY 0')
calc_entry = tk.Entry(main) # creates an entry
calc_entry.grid(row =1, columnspan = 6)
bEquate = tk.Button(main, text="=", command = calculate)
bEquate.grid(row=5, column=3)
bDivision = tk.Button(main, text="/", command = lambda : insert_variable("/"))
bDivision.grid(row=3, column=5)
main.mainloop()
What if I have sqrt() function that gives sqrt sign to the last number? How can I implement it to the calculate() function?
sqrtChr = unichr(0x221A)
def insert_sqrt():
"""inserts sqrt sign"""
global sqrtChr
END = len(calc_entry.get())
equation = calc_entry.get() # takes the whole user's equation from the entry
for i in range(-1,-END-1,-1): # loop that goes from -1,-2,-3 to end-1
if i == -END: # if there are no exceptions like '.' or special sign, inserts sqrt character at beginning of string in the entry
calc_entry.insert(0,sqrtChr)
elif equation[i] == '.': # if there is a dot in equation go to next character in equation
pass
else:
try: # if there is a sign insert sqrt character after it and break loop
int(equation[i])
except ValueError:
calc_entry.insert((END+i+1),sqrtChr)
break

Use
from __future__ import division
and 1/2 will gives you 0.5 - the same eval("1/2")

Related

Rearranging elements in Python

i am new to Python and i cant get this.I have a List and i want to take the input from there and write those in files .
p = ['Eth1/1', 'Eth1/5','Eth2/1', 'Eth2/4','Eth101/1/1', 'Eth101/1/2', 'Eth101/1/3','Eth102/1/1', 'Eth102/1/2', 'Eth102/1/3','Eth103/1/1', 'Eth103/1/2', 'Eth103/1/3','Eth103/1/4','Eth104/1/1', 'Eth104/1/2', 'Eth104/1/3','Eth104/1/4']
What i am trying :
with open("abc1.txt", "w+") as fw1, open("abc2.txt", "w+") as fw2:
for i in p:
if len(i.partition("/")[0]) == 4:
fw1.write('int ' + i + '\n mode\n')
else:
i = 0
while i < len(p):
start = p[i].split('/')
if (start[0] == 'Eth101'):
i += 3
key = start[0]
i += 1
while i < len(p) and p[i].split('/')[0] == key:
i += 1
end = p[i-1].split('/')
fw2.write('confi ' + start[0] + '/' + start[1] + '-' + end[1] + '\n mode\n')
What i am looking for :
abc1.txt should have
int Eth1/1
mode
int Eth1/5
mode
int Eth2/1
mode
int Eth 2/4
mode
abc2.txt should have :
int Eth101/1/1-3
mode
int Eth102/1/1-3
mode
int Eth103/1/1-4
mode
int Eth104/1/1-4
mode
So any Eth having 1 digit before " / " ( e:g Eth1/1 or Eth2/2
)should be in one file that is abc1.txt .
Any Eth having 3 digit before " / " ( e:g Eth101/1/1 or Eth 102/1/1
) should be in another file that is abc2.txt and .As these are in
ranges , need to write it like Eth101/1/1-3, Eth102/1/1-3 etc
Any Idea ?
I don't think you need a regex here, at all. All your items begin with 'Eth' followed by one or more digits. So you can check the length of the items before first / occurs and then write it to a file.
p = ['Eth1/1', 'Eth1/5','Eth2/1', 'Eth2/4','Eth101/1/1', 'Eth101/1/2', 'Eth101/1/3','Eth102/1/1', 'Eth102/1/2', 'Eth102/1/3','Eth103/1/1', 'Eth103/1/2', 'Eth103/1/3','Eth103/1/4','Eth104/1/1', 'Eth104/1/2', 'Eth104/1/3','Eth104/1/4']
with open("abc1.txt", "w+") as fw1, open("abc2.txt", "w+") as fw2:
for i in p:
if len(i.partition("/")[0]) == 4:
fw1.write('int ' + i + '\n mode\n')
else:
fw2.write('int ' + i + '\n mode\n')
I refactored your code a little to bring with-statement into play. This will handle correctly closing the file at the end. Also it is not necessary to iterate twice over the sequence, so it's all done in one iteration.
If the data is not as clean as provided, then you maybe want to use regexes. Independent of the regex itself, by writing if re.match(r'((Eth\d{1}\/\d{1,2})', "p" ) you proof if a match object can be created for given regex on the string "p", not the value of the variable p. This is because you used " around p.
So this should work for your example. If you really need a regex, this will turn your problem in finding a good regex to match your needs without any other issues.
As these are in ranges , need to write it like Eth101/1/1-3, Eth102/1/1-3 etc
This is something you can achieve by first computing the string and then write it in the file. But this is more like a separate question.
UPDATE
It's not that trivial to compute the right network ranges. Here I can present you one approach which doesn't change my code but adds some functionality. The trick here is to get groups of connected networks which aren't interrupted by their numbers. For that I've copied consecutive_groups. You can also do a pip install more-itertools of course to get that functionality. And also I transformed the list to a dict to prepare the magic and then retransformed dict to list again. There are definitely better ways of doing it, but this worked for your input data, at least.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from itertools import groupby
from operator import itemgetter
p = ['Eth1/1', 'Eth1/5', 'Eth2/1', 'Eth2/4', 'Eth101/1/1', 'Eth101/1/2',
'Eth101/1/3', 'Eth102/1/1', 'Eth102/1/2', 'Eth102/1/3', 'Eth103/1/1',
'Eth103/1/2', 'Eth103/1/3', 'Eth103/1/4', 'Eth104/1/1', 'Eth104/1/2',
'Eth104/1/3', 'Eth104/1/4']
def get_network_ranges(networks):
network_ranges = {}
result = []
for network in networks:
parts = network.rpartition("/")
network_ranges.setdefault(parts[0], []).append(int(parts[2]))
for network, ranges in network_ranges.items():
ranges.sort()
for group in consecutive_groups(ranges):
group = list(group)
if len(group) == 1:
result.append(network + "/" + str(group[0]))
else:
result.append(network + "/" + str(group[0]) + "-" +
str(group[-1]))
result.sort() # to get ordered results
return result
def consecutive_groups(iterable, ordering=lambda x: x):
"""taken from more-itertools (latest)"""
for k, g in groupby(
enumerate(iterable), key=lambda x: x[0] - ordering(x[1])
):
yield map(itemgetter(1), g)
# only one line added to do the magic
with open("abc1.txt", "w+") as fw1, open("abc2.txt", "w+") as fw2:
p = get_network_ranges(p)
for i in p:
if len(i.partition("/")[0]) == 4:
fw1.write('int ' + i + '\n mode\n')
else:
fw2.write('int ' + i + '\n mode\n')

Python - Obtain the most frequent word in a sentence, if there is a tie return the word that appears first in alphabetical order

I have written the following code below. It works without errors, the problem that I am facing is that if there are 2 words in a sentence that have been repeated the same number of times, the code does not return the first word in alphabetical order. Can anyone please suggest any alternatives? This code is going to be evaluated in Python 2.7.
"""Quiz: Most Frequent Word"""
def most_frequent(s):
"""Return the most frequently occuring word in s."""
""" Step 1 - The following assumptions have been made:
- Space is the default delimiter
- There are no other punctuation marks that need removing
- Convert all letters into lower case"""
word_list_array = s.split()
"""Step 2 - sort the list alphabetically"""
word_sort = sorted(word_list_array, key=str.lower)
"""Step 3 - count the number of times word has been repeated in the word_sort array.
create another array containing the word and the frequency in which it is repeated"""
wordfreq = []
freq_wordsort = []
for w in word_sort:
wordfreq.append(word_sort.count(w))
freq_wordsort = zip(wordfreq, word_sort)
"""Step 4 - output the array having the maximum first index variable and output the word in that array"""
max_word = max(freq_wordsort)
word = max_word[-1]
result = word
return result
def test_run():
"""Test most_frequent() with some inputs."""
print most_frequent("london bridge is falling down falling down falling down london bridge is falling down my fair lady") # output: 'bridge'
print most_frequent("betty bought a bit of butter but the butter was bitter") # output: 'butter'
if __name__ == '__main__':
test_run()
Without messing too much around with your code, I find that a good solution can be achieved through the use of the index method.
After having found the word with the highest frequency (max_word), you simply call the index method on wordfreq providing max_word as input, which returns its position in the list; then you return the word associated to this index in word_sort.
Code example is below (I removed the zip function as it is not needed anymore, and added two simpler examples):
"""Quiz: Most Frequent Word"""
def most_frequent(s):
"""Return the most frequently occuring word in s."""
""" Step 1 - The following assumptions have been made:
- Space is the default delimiter
- There are no other punctuation marks that need removing
- Convert all letters into lower case"""
word_list_array = s.split()
"""Step 2 - sort the list alphabetically"""
word_sort = sorted(word_list_array, key=str.lower)
"""Step 3 - count the number of times word has been repeated in the word_sort array.
create another array containing the word and the frequency in which it is repeated"""
wordfreq = []
# freq_wordsort = []
for w in word_sort:
wordfreq.append(word_sort.count(w))
# freq_wordsort = zip(wordfreq, word_sort)
"""Step 4 - output the array having the maximum first index variable and output the word in that array"""
max_word = max(wordfreq)
word = word_sort[wordfreq.index(max_word)] # <--- solution!
result = word
return result
def test_run():
"""Test most_frequent() with some inputs."""
print(most_frequent("london bridge is falling down falling down falling down london bridge is falling down my fair lady")) # output: 'down'
print(most_frequent("betty bought a bit of butter but the butter was bitter")) # output: 'butter'
print(most_frequent("a a a a b b b b")) #output: 'a'
print(most_frequent("z z j j z j z j")) #output: 'j'
if __name__ == '__main__':
test_run()

Extracting Numbers from a String Without Regular Expressions

I am trying to extract all the numbers from a string composed of digits, symbols and letters.
If the numbers are multi-digit, I have to extract them as multidigit (e.g. from "shsgd89shs2011%%5swts"), I have to pull the numbers out as they appear (89, 2011 and 5).
So far what I have done just loops through and returns all the numbers incrementally, which I like but I cannot figure out how to make it stop
after finishing with one set of digits:
def StringThings(strng):
nums = []
number = ""
for each in range(len(strng)):
if strng[each].isdigit():
number += strng[each]
else:
continue
nums.append(number)
return nums
Running this value: "6wtwyw66hgsgs" returns ['6', '66', '666']
w
hat simple way is there of breaking out of the loop once I have gotten what I needed?
Using your function, just use a temp variable to concat each sequence of digits, yielding the groups each time you encounter a non-digit if the temp variable is not an empty string:
def string_things(strng):
temp = ""
for ele in strng:
if ele.isdigit():
temp += ele
elif temp: # if we have a sequence
yield temp
temp = "" # reset temp
if temp: # catch ending sequence
yield temp
Output
In [9]: s = "shsgd89shs2011%%5swts"
In [10]: list(string_things(s))
Out[10]: ['89', '2011', '5']
In [11]: s ="67gobbledegook95"
In [12]: list(string_things(s))
Out[12]: ['67', '95']
Or you could translate the string replacing letters and punctuation with spaces then split:
from string import ascii_letters, punctuation, maketrans
s = "shsgd89shs2011%%5swts"
replace = ascii_letters+punctuation
tbl = maketrans(replace," " * len(replace))
print(s.translate(tbl).split())
['89', '2011', '5']
L2 = []
file_Name1 = 'shsgd89shs2011%%5swts'
from itertools import groupby
for k,g in groupby(file_Name1, str.isdigit):
a = list(g)
if k == 1:
L2.append("".join(a))
print(L2)
Result ['89', '2011', '5']
Updated to account for trailing numbers:
def StringThings(strng):
nums = []
number = ""
for each in range(len(strng)):
if strng[each].isdigit():
number += strng[each]
if each == len(strng)-1:
if number != '':
nums.append(number)
if each != 0:
if strng[each].isdigit() == False:
if strng[each-1].isdigit():
nums.append(number)
number = ""
continue;
return nums
print StringThings("shsgd89shs2011%%5swts34");
// returns ['89', '2011', '5', '34']
So, when we reach a character which is not a number, and if the previously observed character was a number, append the contents of number to nums and then simply empty our temporary container number, to avoid it containing all the old stuff.
Note, I don't know Python so the solution may not be very pythonic.
Alternatively, save yourself all the work and just do:
import re
print re.findall(r'\d+', 'shsgd89shs2011%%5swts');

NZEC in python on spoj for AP2

I wrote the following two codes
FCTRL2.py
import sys;
def fact(x):
res = 1
for i in range (1,x+1):
res=res*i
return res;
t = int(raw_input());
for i in range (0,t):
print fact(int(raw_input()));
and
AP2.py
import sys;
t = int(raw_input());
for i in range (0,t):
x,y,z = map(int,sys.stdin.readline().split())
n = (2*z)/(x+y)
d = (y-x)/(n-5)
a = x-(2*d)
print n
for j in range(0,n):
sys.stdout.write(a+j*d)
sys.stdout.write(' ')
print' '
FCTRL2.py is accepted on spoj whereas AP2.py gives NZEC error. Both work fine on my machine and i do not find much difference with regard to returning values from both. Please explain what is the difference in both and how do i avoid NZEC error for AP2.py
There may be extra white spaces in the input. A good problem setter would ensure that the input satisfies the specified format. But since spoj allows almost anyone to add problems, issues like this sometimes arise. One way to mitigate white space issues is to read the input at once, and then tokenize it.
import sys; # Why use ';'? It's so non-pythonic.
inp = sys.stdin.read().split() # Take whitespaces as delimiter
t = int(inp[0])
readAt = 1
for i in range (0,t):
x,y,z = map(int,inp[readAt:readAt+3]) # Read the next three elements
n = (2*z)/(x+y)
d = (y-x)/(n-5)
a = x-(2*d)
print n
#for j in range(0,n):
# sys.stdout.write(a+j*d)
# sys.stdout.write(' ')
#print ' '
print ' '.join([str(a+ti*d) for ti in xrange(n)]) # More compact and faster
readAt += 3 # Increment the index from which to start the next read
The n in line 10 can be a float, the range function expects an integer. Hence the program exits with an exception.
I tested this on Windows with values:
>ap2.py
23
4 7 9
1.6363636363636365
Traceback (most recent call last):
File "C:\martin\ap2.py", line 10, in <module>
for j in range(0,n):
TypeError: 'float' object cannot be interpreted as an integer

How to match the numeric value in a regular expression?

Okay, this is quite an interesting challenge I have got myself into.
My RegEx takes as input lines like the following:
147.63.23.156/159
94.182.23.55/56
134.56.33.11/12
I need it to output a regular expression that matches the range represented. Let me explain.
For example, if the RegEx receives 147.63.23.156/159, then it needs to output a RegEx that matches the following:
147.63.23.156
147.63.23.157
147.63.23.158
147.63.23.159
How can I do this?
Currently I have:
(\d{1,3}\.\d{1,3}\.\d{1,3}\.)(\d{1,3})/(\d{1,3})
$1 contains the first xxx.xxx.xxx. part
$2 contains the lower range for the number
$3 contains the upper range for the number
Regexes are really not a great way to validate IP addresses, I want to make that clear right up front. It is far, far easier to parse the addresses and do some simple arithmetic to compare them. A couple of less thans and greater thans and you're there.
That said, it seemed like it would be a fun exercise to write a regex generator. I came up with a big mess of Python code to generate these regexes. Before I show the code, here's a sample of the regexes it produces for a couple of IP ranges:
1.2.3.4 to 1.2.3.4 1\.2\.3\.4
147.63.23.156 to 147.63.23.159 147\.63\.23\.15[6-9]
10.7.7.10 to 10.7.7.88 10\.7\.7\.([1-7]\d|8[0-8])
127.0.0.0 to 127.0.1.255 127\.0\.[0-1]\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))
I'll show the code in two parts. First, the part that generates regexes for simple integer ranges. Second, the part that handles full IP addresses.
Matching number ranges
The first step is to figure out how to generate a regex that matches an arbitrary integer range, say 12-28 or 0-255. Here's an example of the regexes my implementation comes up with:
156 to 159 15[6-9]
1 to 100 [1-9]|[1-9]\d|100
0 to 255 \d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5])
And now the code. There are numerous comments inline explaining the logic behind it. Overall it relies on a lot of recursion and special casing to try to keep the regexes lean and mean.
import sys, re
def range_regex(lower, upper):
lower, upper = str(lower), str(upper)
# Different lengths, for instance 1-100. Combine regex(1-9) and
# regex(10-100).
if len(lower) != len(upper):
return '%s|%s' % (
range_regex(lower, '9' * len(lower)),
range_regex(10 ** (len(lower)), upper)
)
ll, lr = lower[0], lower[1:]
ul, ur = upper[0], upper[1:]
# One digit numbers.
if lr == '':
if ll == '0' and ul == '9':
return '\\d'
else:
return '[%s-%s]' % (ll, ul)
# Same first digit, for instance 12-14. Concatenate "1" and regex(2-4).
elif ll == ul:
return ll + sub_range_regex(lr, ur)
# All zeros to all nines, for instance 100-399. Concatenate regex(1-3)
# and the appropriate number of \d's.
elif lr == '0' * len(lr) and ur == '9' * len(ur):
return range_regex(ll, ul) + '\\d' * len(lr)
# All zeros on left, for instance 200-649. Combine regex(200-599) and
# regex(600-649).
elif lr == '0' * len(lr):
return '%s|%s' % (
range_regex(lower, str(int(ul[0]) - 1) + '9' * len(ur)),
range_regex(ul + '0' * len(ur), upper)
)
# All nines on right, for instance 167-499. Combine regex(167-199) and
# regex(200-499).
elif ur == '9' * len(ur):
return '%s|%s' % (
range_regex(lower, ll + '9' * len(lr)),
range_regex(str(int(ll[0]) + 1) + '0' * len(lr), upper)
)
# First digits are one apart, for instance 12-24. Combine regex(12-19)
# and regex(20-24).
elif ord(ul[0]) - ord(ll[0]) == 1:
return '%s%s|%s%s' % (
ll, sub_range_regex(lr, '9' * len(lr)),
ul, sub_range_regex('0' * len(ur), ur)
)
# Far apart, uneven numbers, for instance 15-73. Combine regex(15-19),
# regex(20-69), and regex(70-73).
else:
return '%s|%s|%s' % (
range_regex(lower, ll + '9' * len(lr)),
range_regex(str(int(ll[0]) + 1) + '0' * len(lr),
str(int(ul[0]) - 1) + '9' * len(ur)),
range_regex(ul + '0' * len(ur), upper)
)
# Helper function which adds parentheses when needed to sub-regexes.
# Sub-regexes need parentheses if they have pipes that aren't already
# contained within parentheses. For example, "6|8" needs parentheses
# but "1(6|8)" doesn't.
def sub_range_regex(lower, upper):
orig_regex = range_regex(lower, upper)
old_regex = orig_regex
while True:
new_regex = re.sub(r'\([^()]*\)', '', old_regex)
if new_regex == old_regex:
break
else:
old_regex = new_regex
continue
if '|' in new_regex:
return '(' + orig_regex + ')'
else:
return orig_regex
Matching IP address ranges
With that capability in place, I then wrote a very similar-looking IP range function to work with full IP addresses. The code is very similar to the code above except that we're working in base 256 instead of base 10, and the code throws around lists instead of strings.
import sys, re, socket
def ip_range_regex(lower, upper):
lower = [ord(c) for c in socket.inet_aton(lower)]
upper = [ord(c) for c in socket.inet_aton(upper)]
return ip_array_regex(lower, upper)
def ip_array_regex(lower, upper):
# One octet left.
if len(lower) == 1:
return range_regex(lower[0], upper[0])
# Same first octet.
if lower[0] == upper[0]:
return '%s\.%s' % (lower[0], sub_regex(ip_array_regex(lower[1:], upper[1:])))
# Full subnet.
elif lower[1:] == [0] * len(lower[1:]) and upper[1:] == [255] * len(upper[1:]):
return '%s\.%s' % (
range_regex(lower[0], upper[0]),
sub_regex(ip_array_regex(lower[1:], upper[1:]))
)
# Partial lower subnet.
elif lower[1:] == [0] * len(lower[1:]):
return '%s|%s' % (
ip_array_regex(lower, [upper[0] - 1] + [255] * len(upper[1:])),
ip_array_regex([upper[0]] + [0] * len(upper[1:]), upper)
)
# Partial upper subnet.
elif upper[1:] == [255] * len(upper[1:]):
return '%s|%s' % (
ip_array_regex(lower, [lower[0]] + [255] * len(lower[1:])),
ip_array_regex([lower[0] + 1] + [0] * len(lower[1:]), upper)
)
# First octets just 1 apart.
elif upper[0] - lower[0] == 1:
return '%s|%s' % (
ip_array_regex(lower, [lower[0]] + [255] * len(lower[1:])),
ip_array_regex([upper[0]] + [0] * len(upper[1:]), upper)
)
# First octets more than 1 apart.
else:
return '%s|%s|%s' % (
ip_array_regex(lower, [lower[0]] + [255] * len(lower[1:])),
ip_array_regex([lower[0] + 1] + [0] * len(lower[1:]),
[upper[0] - 1] + [255] * len(upper[1:])),
ip_array_regex([upper[0]] + [0] * len(upper[1:]), upper)
)
If you just need to build them one at at time, this website will do the trick.
If you need code, and don't mind python, this code does it for any arbitrary numeric range.
If it's for Apache... I haven't tried it, but it might work:
RewriteCond %{REMOTE_ADDR} !<147.63.23.156
RewriteCond %{REMOTE_ADDR} !>147.63.23.159
(Two consecutive RewriteConds are joined by a default logical AND)
Just have to be careful with ranges with differing number of digits (e.g. 95-105 should be broken into 95-99 and 100-105, since it is lexicographic ordering).
I absolutely agree with the commenters, a pure-regex solution would be the wrong tool for the job here. Just use the regular expression you already have to extract the prefix, minimum, and maximum values,
$prefix, $minimum, $maximum = match('(\d{1,3}\.\d{1,3}\.\d{1,3}\.)(\d{1,3})/(\d{1,3})', $line).groups()
then test your IP address against ${prefix}(\d+),
$lastgroup = match($prefix + '(\d+)', $addr).groups()[0]
and compare that last group to see if it falls within the proper range,
return int($minimum) <= int($lastgroup) <= int($maximum)
Code examples are pseudocode, of course - convert to your language of choice.
To my knowledge, this can't be done with straight up regex, but would also need some code behind it. For instance, in PHP you could use the following:
function make_range($ip){
$regex = '#(\d{1,3}\.\d{1,3}\.\d{1,3}\.)(\d{1,3})/(\d{1,3})#';
if ( preg_match($regex, $ip, $matches) ){
while($matches[1] <= $matches[2]){
print "{$matches[0]}.{$matches[1]}";
$matches[1]++;
}
} else {
exit('not a supported IP range');
}
}
For this to work with a RewriteCond, I think some black magic would be in order...
How is this going to be used with RewriteCond, anyways? Do you have several servers and want to just quickly make a .htaccess file easily? If so, then just add that function to a bigger script that takes some arguments and burps out a .htaccess file.