I am working on an simple parser to handle expression such as:
"""
FOO*1.5
+
BAR*3
"""
To get an end numeric result, where FOO and BAR are replaced at runtime by the values returned by external function executions. For example: FOO ---> def foo():return 2 and BAR ---> def bar():return 4. Which in our example would yield (2*1.5)+(4*3) = 3+12 = 14.
This is what I have so far:
from pyparsing import *
from decimal import Decimal
WEIGHT_OPERATORS = ['*', '/']
NUMERIC_OPERATORS = ['+', '-']
def make_score(input):
if input[0] == 'FOO':
return 5
elif input[0] == 'BAR':
return 10
return 1
def make_decimal(input):
try:
return Decimal(input[0])
except ValueError:
pass
return 0
SCORE = Word(alphanums + '_').setParseAction(make_score)
WEIGHT_OPERATOR = oneOf(WEIGHT_OPERATORS)
WEIGHT = Word(nums+'.').setParseAction(make_decimal)
INDIVIDUAL_EXPRESSION = SCORE('score') \
+ WEIGHT_OPERATOR('weight_operator') \
+ WEIGHT('weight')
print INDIVIDUAL_EXPRESSION
print INDIVIDUAL_EXPRESSION.parseString(expression).dump()
Up to here, all works well.
What I miss is the ability to "chain" INDIVIDUAL_EXPRESSIONs together to add/substract them together, as in the simple example above. I have tried:
GLOBAL_EXPRESSION = infixNotation(
INDIVIDUAL_EXPRESSION,
[
(NUMERIC_OPERATORS, 2, opAssoc.RIGHT,)
# or (NUMERIC_OPERATORS, 1, opAssoc.LEFT,), etc... :(
]
)
print GLOBAL_EXPRESSION
print GLOBAL_EXPRESSION.parseString(expression).dump()
Nope.
And:
INDIVIDUAL_EXPRESSION = SCORE('score') \
+ WEIGHT_OPERATOR('weight_operator') \
+ WEIGHT('weight')
+ ZeroOrMore(NUMERIC_OPERATORS)
To get the final list or dict that would easy to compute, to no avail. I am doing something wrong, but what?
Try this:
GLOBAL_EXPRESSION = OneOrMore(Group(INDIVIDUAL_EXPRESSION) + Optional(oneOf(NUMERIC_OPERATORS)))
GE_LIST = Group(delimitedList(GLOBAL_EXPRESSION))
print GE_LIST.parseString(expression)
Related
I wanna get all integer solutions in a limited time, is it possible?
This is a linear, integer constraint satisfaction problem, which can be solved efficiently by OR Tools' CP-SAT. I've modified their example to solve your problem in Python:
from ortools.sat.python import cp_model
class VarArraySolutionPrinter(cp_model.CpSolverSolutionCallback):
"""Print intermediate solutions."""
def __init__(self, variables):
cp_model.CpSolverSolutionCallback.__init__(self)
self.__variables = variables
self.__solution_count = 0
def on_solution_callback(self):
self.__solution_count += 1
for v in self.__variables:
print('%s=%i' % (v, self.Value(v)), end=' ')
print()
def solution_count(self):
return self.__solution_count
def SearchForAllSolutionsSampleSat():
"""Showcases calling the solver to search for all solutions."""
# Creates the model.
model = cp_model.CpModel()
p = [1, 2, 3, 4]
ceq = 30
cgeq = 2
N = len(p)
# Creates the variables
x = [model.NewIntVar(0, 100, f'x{i}') for i in range(N)]
# Create the constraints.
model.Add(sum([xi*pi for xi, pi in zip(x, p)]) == ceq)
model.Add(sum(x) >= cgeq)
# Create a solver and solve.
solver = cp_model.CpSolver()
solution_printer = VarArraySolutionPrinter(x)
status = solver.SearchForAllSolutions(model, solution_printer)
print('Status = %s' % solver.StatusName(status))
print('Number of solutions found: %i' % solution_printer.solution_count())
SearchForAllSolutionsSampleSat()
How can I extract '1' '11' and '111' from this list ?
T0 = ['4\t1\t\n', '0.25\t11\t\n', '0.2\t111\t\n']
to extract '4', '0.25' and '0.2' I used this :
def extract(T0):
T1 = []
for i in range(0, len(T0)):
pos = T0[i].index('\t')
T1.append(resultat[i][0: pos])
return T1
then I got :
T1 = ['4','0.25','0.2']
but for the rest I don't know how to extract it
can you help me please?
Using your code as base, it can be done as below. Will return as string if its alphabet, otherwise return as decimal integer.
def extract(T0):
T1=[]
for i in range len(T0):
tmp = T0[i].split('\t')[1]
if tmp.isalpha():
T1.append(tmp)
else:
T1.append(int(tmp))
return T1
Alternatively, try below for a more compact code using list comprehension
def extract(T0):
# return as string if its alphabet else return as decimal integer
# change int function to float if wanna return as float
tmp = [i.split('\t')[1] for i in T0]
return [i if i.isalpha() else int(i) for i in tmp]
Example
T0= ['X\tY\tf(x.y)\n', '0\t0\t\n', '0.1\t10\t\n', '0.2\t20\t\n', '0.3\t30\t\n']
extract(T0) # return ['Y', 0, 10, 20, 30]
You can accomplish this with the re module and a list comprehension.
import re
# create a regular expression object
regex = re.compile(r'[0-9]{1,}\.{0,1}[0-9]{0,}')
# assign the input list
T0 = ['4\t1\t\n', '0.25\t11\t\n', '0.2\t111\t\n']
# get a list of extractions using the regex
extractions = [x for x in [re.findall(regex, e) for e in T0]]
print extractions
# => [['4', '1'], ['0.25', '11'], ['0.2', '111']]
I'm very new to python and I've been working on a basic calculator within python for the last few hours (rhetorical I know, given what python has built in, but it's part of my learning process), I've run into an error I can't seem to fix, generally I'm able to get my scripts on their feet and running with the assistance of a couple of Google searches but this one has me stumped. I'm getting a syntax error where I have an else, and while at first I was pretty sure it was a structure issue, rewriting the script didn't fix anything, vague I know, so here's the script (I've marked the spot with a comment) :
def Calculator():
tempnums = [] #stores nums only
tempfuncs = [] #stores funcs only
tmpfuncs = {} #stores funcs only
times = lambda multiply: tempnums[0]*tempnums[1]
div = lambda divide: tempnums[0]%tempnums[1]
plus = lambda add: tempnums[0]+tempnums[1]
minus = lambda subtract:tempnums[0]-tempnums[1]
done = 0
varnum = 0
xtimes = 0
divtimes = 0
plustimes = 0
mintimes = 0
while done == 0: #USER INPUT PROCESS
varnum = varnum + 1
tempint = input() #nums
exec("num%d = tempint" % (varnum))
function = raw_input() #functions
if function != "=":
if function == 'x':
if x not in tmpfuncs:
xtimes = xtimes + 1
tmpfuncs[x] = times
else:
xtimes = xtimes + 1
exec("tmpfuncs[x%d] = times" % (xtimes)
else: #ERROR COMES HERE
if function == '//':
if dv not in tmpfuncs:
divtimes = divtimes + 1
tmpfuncs[dv] = div
else:
divtimes = divtimes + 1
exec("tmpfuncs[dv%d] = div" % (divtimes)
if function == '+':
if pls not in tmpfuncs:
plustimes = plustimes + 1
tmpfuncs[pls] = plus
else:
plustimes = plustimes + 1
exec("tmpfuncs[pls%d] = plus" % (plustimes)
if function == '-':
if mn not in tmpfuncs:
mintimes = mintimes + 1
tmpfuncs[mn] = minus
else:
mintimes = mintimes + 1
exec("tmpfuncs[mn%d] = minus" % (mintimes)
else: #user has selected to calculate input
done = 1
for i in range(1, varnum + 1):
exec("tempnums.append(num%d)" % (i)) #adding nums to a list with dynamic var names
print tmpfuncs
#next we'll make it so that tempnums[0] is the changing result as we use tempnums 0 and 1 to calculate the answer, deleting one as we go until there is only zero
Calculator()
Calculator()
I'm hoping this is legible as I'm posting from mobile (as a matter of fact I'm writing this from mobile as well).
The line above the else is missing a closing parens:
exec("tmpfuncs[x%d] = times" % (xtimes)
should be
exec("tmpfuncs[x%d] = times" % (xtimes))
The same error occurs in many other of your exec lines. Also, I suggest you consider restructuring your code so you do not need to use exec at all.
hey guys:)im sorry for all the code but i feel its necessary for u to see everything..
i tried everything... i hidden prints in the code, debugging for ten times, triple checked the built in methods, and still, the .crawl() method dosnt remove any object from the final_list.
the object of my assignment is to built two classes:
Web_page : holds data of a web page.(the pages come in the form of html files saved in a folder on my desktop. Crawler: compare between pages and hold a list of the uniqe pages---> final_list
import re
import os
def remove_html_tags(s):
tag = False
quote = False
out = ""
for c in s:
if c == '<' and not quote:
tag = True
elif c == '>' and not quote:
tag = False
elif (c == '"' or c == "'") and tag:
quote = not quote
elif not tag:
out = out + c
return out
def lev(s1, s2):
return lev_iter(s1, s2, dict())
def lev_iter(s1, s2, mem):
(i,j) = (len(s1), len(s2))
if (i,j) in mem:
return mem[(i,j)]
s1_low = s1.lower()
s2_low = s2.lower()
if len(s1_low) == 0 or len(s2_low) == 0:
return max(len(s1_low), len(s2_low))
d1 = lev_iter(s1_low[:-1], s2_low, mem) + 1
d2 = lev_iter(s1_low, s2_low[:-1], mem) + 1
last = 0 if s1_low[-1] == s2_low[-1] else 1
d3 = lev_iter(s1_low[:-1], s2_low[:-1], mem) + last
result = min(d1, d2, d3)
mem[(i,j)] = result
return result
def merge_spaces(content):
return re.sub('\s+', ' ', content).strip()
""" A Class that holds data on a Web page """
class WebPage:
def __init__(self, filename):
self.filename = filename
def process(self):
f = open(self.filename,'r')
LINE_lst = f.readlines()
self.info = {}
for i in range(len(LINE_lst)):
LINE_lst[i] = LINE_lst[i].strip(' \n\t')
LINE_lst[i] = remove_html_tags(LINE_lst[i])
lines = LINE_lst[:]
for line in lines:
if len(line) == 0:
LINE_lst.remove(line)
self.body = ' '.join(LINE_lst[1:])
self.title = LINE_lst[0]
f.close()
def __str__(self):
return self.title + '\n' + self.body
def __repr__(self):
return self.title
def __eq__(self,other):
n = lev(self.body,other.body)
k = len(self.body)
m = len(other.body)
return float(n)/max(k,m) <= 0.15
def __lt__(self,other):
return self.title < other.title
""" A Class that crawls the web """
class Crawler:
def __init__(self, directory):
self.folder = directory
def crawl(self):
pages = [f for f in os.listdir(self.folder) if f.endswith('.html')]
final_list = []
for i in range(len(pages)):
pages[i] = WebPage(self.folder + '\\' + pages[i])
pages[i].process()
for k in range(len(final_list)+1):
if k == len(final_list):
final_list.append(pages[i])
elif pages[i] == final_list[k]:
if pages[i] < final_list[k]:
final_list.append(pages[i])
final_list.remove(final_list[k])
break
print final_list
self.pages = final_list
everything works fine besides this freaking line final_list.remove(final_list[k]). help please? whats wrong here?
I'm not sure why your code doesn't work, it's difficult to test it because I don't know what kind of input should end up calling remove().
I suggest following these steps:
Make sure that remove() is called at some point.
remove() relies on your __eq__() method to find the item to remove, so make sure that __eq__() isn't the culprit.
As a side note, you will probably want to replace this:
self.folder + '\\' + pages[i]
with:
import os.path
# ...
os.path.join(self.folder, page[i])
This simple change should make your script work on all operating systems, rather than on Windows only. (GNU/Linux, Mac OS and other Unix-like OS use “/” as path separator.)
Please also consider replacing loops of this form:
for i in range(len(sequence)):
# Do something with sequence[i]
with:
for item in sequence:
# Do something with item
If you need the item index, use enumerate():
for i, item in enumerate(sequence):
So I have an Article class that models the articles in a store. When I create a new article, I want it to have an EAN 13 code. So I initialize the article with a 12 digits code and use the check_ean13() funtion to retrieve the control digit. It works but seems like in any moment, when the object is created, rewrite the ean13 attribute and replaces it for None. Any ideas?
Main
if __name__ == "__main__":
# create article
art1 = Article("123456789087", "Article 1", 145.6, 200.0)
print art1
print art1.get_ean13()
class Article
class Article:
def __init__(self, cod, art_name, cost, listprice):
self.ean13 = self.set_ean13(cod)
self.art_name = art_name
self.cost = cost
self.listprice = listprice
self.commission = None
self.promotion=[]
def get_ean13(self):
return self.ean13
def set_ean13(self,cod):
cd = self.check_ean13(cod)
ean13 = cod + str(cd)
self.ean13=ean13
def check_ean13(self, code):
checksum = 0
for i, digit in enumerate(reversed(code)):
checksum += int(digit) * 3 if (i % 2 == 0) else int(digit)
return (10 - (checksum % 10)) % 10
output:
None - Article 1 list price: 400.0
None
self.ean13 = self.set_ean13(cod)
set_ean13 doesn't return anything, so you're effectively doing self.ean13 = None here. Just call the method without assigning the result.
self.set_ean13(cod)