Regexp проблема, связанная с калькулятором обратной польской

Я пытаюсь использовать регулярное выражение для решения проблемы обратного польского калькулятора, но у меня возникают проблемы с преобразованием математических выражений в обычную форму.

Я написал:

puts '35 29 1 - 5 + *'.gsub(/(\d*) (\d*) (\W)/, '(\1\3\2)')

который печатает:

35 (29-1)(+5) *

ожидаемый

(35*((29-1)+5)) 

но я получаю другой результат. Что я делаю неправильно?

1 ответ

Я предполагаю, что вы имели в виду, что вы пытались

puts '35 29 1 - 5 + *'.gsub(/(\d*) (\d*) (\W)/, '(\1\3\2)')
                    ^           ^

В любом случае, вы должны использовать квантификатор + вместо *, так как в противном случае вы будете соответствовать пустой строке для \d* как один из ваших захватов, следовательно, (+5):

/(\d+) (\d+) (\W)/

Я бы далее расширил / ограничил выражение чем-то вроде:

/([\d+*\/()-]+)\s+([\d+*\/()-]+)\s+([+*\/-])/
 |             |  |             |   |
 |             |  |             |   Valid operators, +, -, *, and /.
 |             |  |             |   
 |             |  |             Whitespace.
 |             |  |                 
 |             |  Arbitrary atom, e.g. "35", "(29-1)", "((29-1)+5)".
 |             |                    
 |             Whitepsace.                  
 |
 Arbitrary atom, e.g. "35", "(29-1)", "((29-1)+5)".

... и вместо того, чтобы использовать gsubиспользовать sub в while Цикл, который завершается, когда обнаруживает, что больше нет замен. Это очень важно, потому что в противном случае вы нарушите порядок операций. Например, взгляните на эту демонстрацию Rubular. Вы можете увидеть это, используя gsubВы могли бы потенциально заменить вторую триаду атомов, "5 + *", когда действительно вторая итерация должна заменить "более раннюю" триаду после замены первой триады!

ВНИМАНИЕ: - (минус) символ должен появляться первым или последним в классе символов, так как в противном случае он будет указывать диапазон! (Спасибо @JoshuaCheek.)

Другие вопросы по тегам