2015-05-13 4 views
0

У меня есть строка, представляющая основные алгебраические операции, например:Scala - строка алгебраических операций

"42 * 67 + 4" 

Я хотел бы функцию типа

function (operation: String) : Int = {} 

таким образом, что она принимает строку алгебраических операций и возвращает фактическое конечное значение, в этом случае: 2818

Я бы знал, как извлечь числа из такой строки, но у меня нет четкого представления о том, как извлечь мат математические операции, такие как '+', '-', '*', '/' и фактически вычислять их.

+2

Вы можете использовать [ScriptEngine] (http://docs.oracle.com/javase/7/docs/api/javax/script/ScriptEngine.html), хотя существует множество способов анализа и оценки выражений. –

ответ

2

Это довольно просто реализовать Shunting-yard algorithm делать такого рода вычислений без каких-либо внешних библиотек:

def calculate(operation: String): Int = { 
    var results: List[Int] = Nil 
    var operators: List[String] = Nil 

    def precedence(operator: String) = operator match { 
    case "+" | "-" => 0 
    case "*" | "/" => 1 
    } 

    def execute(operator: String): Unit = { 
    (results, operator) match { 
     case (x :: y :: rest, "+") => results = (y + x) :: rest 
     case (x :: y :: rest, "-") => results = (y - x) :: rest 
     case (x :: y :: rest, "*") => results = (y * x) :: rest 
     case (x :: y :: rest, "/") => results = (y/x) :: rest 
     case (_, _) => throw new RuntimeException("Not enough arguments") 
    } 
    } 

    for (term <- "[1-9][0-9]*|[-+/*]".r.findAllIn(operation)) { 
    util.Try(term.toInt) match { 
     case util.Success(number) => results ::= number 
     case _ => 
     val (operatorsToExecute, rest) = 
      operators.span(op => precedence(op) >= precedence(term)) 
     operatorsToExecute foreach execute 
     operators = term :: rest 
    } 
    } 
    operators foreach execute 

    results match { 
    case res :: Nil => res 
    case _ => throw new RuntimeException("Too many arguments") 
    } 
} 

Это использует целочисленное деление:

scala> calculate("3/2") 
res0: Int = 1 

И имеет правильный приоритет добавления и умножения:

scala> calculate("2 + 2 * 2") 
res1: Int = 6 

Поддержка:

    более
  • видов операций,
  • круглых скобок, например, 2 * (2 + 2),
  • вычисления с плавающей точкой,
  • лучше тестирование содержания формулы (в настоящее время он просто игнорирует все символы, кроме цифр и операторов)
  • не метание ошибки (например, возвращающиеся Try[Int], Option[Int] и т.д. вместо текущее поведение при возврате голого Int или выброса ошибки)

оставлен в качестве упражнения для чтения.

Для более сложных вещей, конечно, было бы лучше использовать scala-parser-combinators или какую-либо стороннюю парсинговую библиотеку, как предложено в других ответах.

0

Итак, @ Gábor Bakos опубликовал свой шуточный комментарий, пока я все еще сочинял и тестировал свой шуточный ответ, но я все равно отправлю его.

Примечание: он работает. Иногда. Немного. Примечание2: это шутка!

def function(operation: String) = { 
    val js = new javax.script.ScriptEngineManager().getEngineByName("JavaScript") 
    js.eval(operation) match { case i: Integer => i.asInstanceOf[Int] } 
} 

function("42 * 67 + 4") 
// => 2818 : Int 
+0

Извините, но я не компьютерные ученые, поэтому мое чувство юмора отличается от вашего, и я не получаю ваши шутки – mastro

Смежные вопросы