我已经困住了几天的问题,我无法想出一个解决方案。我有一个代码,其中函数接受一串运算符和操作数并返回它们的列表。该函数用于查找parantheses,如果找到它们,它会使用parantheses中的字符串调用自身,并将其作为列表附加到先前创建的空列表中。例如,如果我发送一个字符串“= int int”,则返回列表将是[“=”,“int”,“int”]。如果我发送一个字符串“+(+ int int)int”,返回列表将是[“+”,[“+”,“int”,“int”],“int”]。
但是,当发送“=(+ int int)(+ int int)”形式的字符串时,会出现问题,这意味着一个接一个地包含两个parantheses的字符串。返回列表变为 [“=”,[“+”,“int”,“int”,[“+”,“int”,“int”]]],但想要的结果应该是: [“=”,[“+”,“int”,“int”],[“+”,“int”,“int”]]。代码如下所示,我确实需要一些帮助来确定它的错误。
def convert(string):
string=" "+string
lst = []
i = 0
while i < len(string):
if string[i] == "(":
p = 0 #keeps track of parantheses
i2 = 0
for i2 in range(len(string[i+1:])):
if i2 == ")" and p == 0:
break
elif i2 == "(":
p += 1
elif i2 == ")" and p > 0:
p -= 1
lst += [convert(string[i+1:i+1+i2+1])]
i += i2
if string[i] == " " and string[i+1] != "(":
try:
lst += [getWord(string[i::])]
except:
pass
i += 1
return lst
我真的很感谢你的帮助,谢谢!
编辑:该函数还使用另一个返回单词的函数。
def getWord(string):
word = string.split()[0]
for i in range(len(word)):
if word[i] == ')':
word = word[0:i]
break
return word
Testrun:
>>> convert("> (+ int int)(quotient real real)")
['>', ['+', 'int', 'int', ['quotient', 'real', 'real']]]
答案 0 :(得分:1)
您遇到的一个问题是设置i2
以循环range()
,然后尝试将i2
与字符串进行比较。 (例如:if i2 == ")"
)。
此代码已经过测试并可以使用:
def convert(string):
string=" "+string
lst = []
i = 0
while i < len(string)-1:
if string[i] == "(":
p = 0 #keeps track of parantheses
i2 = 0
for i2 in range(i+1, len(string)):
if string[i2] == ")" and p == 0:
break
elif string[i2] == "(":
p += 1
elif string[i2] == ")" and p > 0:
p -= 1
lst += [convert(string[i+1:i2])]
i = i2
if string[i] == " " and string[i+1] != "(":
try:
lst += [getWord(string[i::])]
except:
pass
i += 1
return lst
这是我的测试运行:
>>> convert("> (+ int int)(quotient real real)")
['>', ['+', 'int', 'int'], ['quotient', 'real', 'real']]
答案 1 :(得分:0)
此函数(不需要getWord()函数):
def convert(string):
rc = []
cstr = ''
idx = 0
while idx < len(string):
if string[idx] == '(':
rc.append(convert(string[idx+1:]))
inc = string[idx+1:].find(')')
if inc >= 0:
idx += (inc + 1)
elif string[idx] == ')':
if len(cstr):
rc.append(cstr)
cstr = ''
return rc
elif string[idx] == ' ':
if len(cstr):
rc.append(cstr)
cstr = ''
else:
cstr += string[idx]
idx += 1
if len(cstr):
rc.append(cstr)
return rc
答案 2 :(得分:0)
IMO,对于像这样的问题,应该使用解析器库。我喜欢Parcon。
为什么然后,你问,是否应该使用Parser Library?因为更容易推理出更高层次抽象的代码。虽然cforbish解决了你完美的问题,但他没有解决代码中的其他缺陷。以这些行为例:
print convert('+ (- int int) (* (/ hey ho) bar')
print convert('+ (- int int) (* (/ hey ho huh))')
print convert('+ (- int int) (* (/ + -))')
结果:
['+', ['-', 'int', 'int'], ['*', ['/', 'hey', 'ho'], 'ba']]
['+', ['-', 'int', 'int'], ['*', ['/', 'hey', 'ho', 'huh']]]
['+', ['-', 'int', 'int'], ['*', ['/', '+', '-']]]
在第一行中,它错误地窃取 bar 的最后一个字符,因为缺少右括号。在第二行中,它接受二元运算符的第三个操作数。在第三行中,它接受运算符作为操作数。除以加减去的结果是什么?
这是一个更好(也更短)的解决方案:
from parcon import Forward, Word, alphanum_chars
Expr = Forward()
Operand = Word(alphanum_chars) | '(' + Expr + ')'
Operator = Word(alphanum_chars) | Word('+-*/<>', max=1)
Expr << (Operator + Operand + Operand)[list]
def convert(s):
return Expr.parse_string(s)
print convert('+ (- int int) (* (/ hey ho) bar)')
结果:
['+', ['-', 'int', 'int'], ['*', ['/', 'hey', 'ho'], 'bar']]
上面的错误输入字符串会产生错误,例如:
print convert('+ (- int int) (* (/ + -))')
结果:
Traceback (most recent call last):
File "convstr.py", line 80, in <module>
print convert('+ (- int int) (* (/ + -))')
File "convstr.py", line 42, in convert
return Expr.parse_string(s)
File "C:\Programme\Python\2.7.2\lib\site-packages\parcon\__init__.py", line 645, in parse_string
raise ParseException("Parse failure: " + format_failure(result.expected), result.expected)
parcon.ParseException: Parse failure: At position 20: expected one of any char in "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "("
代码很容易理解:
Expr = Forward()
这意味着:我将使用Expr,但实际上我将在稍后定义。
Operand = Word(alphanum_chars) | '(' + Expr + ')'
操作数可以是仅包含字母数字字符的单词,也可以是包含在Parens中的Expr。
Operator = Word(alphanum_chars) | Word('+-*/<>', max=1)
运算符是一个只包含字母数字字符的单词,或者是由+, - ,*,/,&lt;,&gt;中的单个字符组成的单词。
Expr << (Operator + Operand + Operand)[list]
这里我们最终定义了Expr是什么:一个运算符后跟两个操作数。 [list]
告诉parcon每个这样的三元组应该包含在列表中。否则,所有解析的标记都会放在一个长平面序列中,如下所示:
('+', '-', 'int', 'int', '*', '/', 'hey', 'ho', 'bar')