将列表作为对象附加到现有列表

时间:2013-11-30 16:03:26

标签: python

我已经困住了几天的问题,我无法想出一个解决方案。我有一个代码,其中函数接受一串运算符和操作数并返回它们的列表。该函数用于查找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']]]

3 个答案:

答案 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')