2013-11-30 3 views
1

У меня возникла проблема в течение нескольких дней, и я не могу найти решение. У меня есть код, в котором функция принимает строку операторов и операндов и возвращает их список. Функция предназначена для поиска скобок, и в случае ее обнаружения она напоминает себя со строкой внутри скобок и добавляет ее в список в ранее созданный пустой список. Например, если я отправляю строку «= int int», возвращаемый список будет ["=", "int", "int"]. Если я отправил строку «+ (+ int int) int», то возвращаемый список будет [«+», [«+», «int», «int»], «int»].Добавление списка как объекта в существующий список

Однако проблема возникает, когда строка в форме «= (+ int int) (+ int int)» отправляется, то есть строка с двумя скобками одна за другой. Возвращаемый список становится ["=", ["+", "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 

Я очень благодарен за вашу помощь, спасибо!

EDIT: функция также использует другую функцию, которая возвращает слово.

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']]] 

ответ

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']] 
+0

Большое спасибо за помощь! – CobraAn

+0

Добро пожаловать! – bitoffdev

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 
+0

Спасибо, это работает! – CobraAn

0

IMO, для такой проблемы следует использовать библиотеку синтаксического анализатора. Мне нравится Parcon.

Почему же вы спрашиваете, следует ли использовать библиотеку Parser? Потому что легче рассуждать о коде, который живет на более высоком уровне абстракции. В то время как 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'], ['*', ['/', '+', '-']]] 

В первой строке он ошибочно крадет последний символ бар, из-за отсутствующей закрывающей скобкой. Во второй строке он принимает третий операнд для двоичного оператора. И в третьей строке он принимает операторы как операнды. Каков результат деления плюса на минус?

Вот лучше (и гораздо короче) решение:

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 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", "(" 

код достаточно легко понять:

Expr = Forward() 

Это означает: я собираюсь использовать Expr, но то, что это на самом деле я определю позже.

Operand = Word(alphanum_chars) | '(' + Expr + ')' 

Операнд либо слово, содержащее только буквенно-цифровые символы или это в Expr, заключенный в круглых скобках.

Operator = Word(alphanum_chars) | Word('+-*/<>', max=1) 

Эксплуатант либо слово, содержащее только буквенно-цифровые знаки или это слово, состоящее из одного символа из +, -, *, /, <,>.

Expr << (Operator + Operand + Operand)[list] 

Здесь мы, наконец, определим, что такое Expr: оператор, за которым следуют два операнда. [list] говорит parcon, что каждая такая тройка должна быть завернута в список. В противном случае все разобранные tokens будут помещаться в одну длинную плоскую последовательность следующим образом:

('+', '-', 'int', 'int', '*', '/', 'hey', 'ho', 'bar') 
Смежные вопросы