БлогNot. Оценивание арифметических выражений "на лету" - как реализовать максимально прос...

Оценивание арифметических выражений "на лету" - как реализовать максимально просто?

Без приоритета, но зато рекурсивно, в этом блоге арифметические выражения уже как-то считались на C++ :)

Но "нормальную" оценивалку выражений, наверное, удобнее всего написать на интерпретируемом языке, можно на том же Javascript.

При этом, реализуем наш разбор выражения прямо в процессе ввода (по событию onkeyup яваскрипта) и заставим его быть "толерантным", то есть, всё, что он не смог проинтерпретировать, он просто "вывалит" в поле ответа.

Функция evalExp получает единственный аргумент - строку с выражением, которое нужно оценить, и устроена как замыкание, то есть, пригодна к встраиванию в любой другой проект. При этом разбор довольно короток за счёт использования регулярных выражений, без которых современное программирование трудно себе представить :) Деление на ноль и переполнение яваскрипту тоже не страшны, он просто вернёт своё любимое Infinity или NaN.

В качестве теста, выражение 1 -- 2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10 дало результат 7001, я проверил в Excel :) Ниже показан скрипт в работе и его полный код.

Сервис недоступен из-за отключённого Javascript в браузере

<script type="text/javascript">
function evalExp (s) {
 s = s.replace(/\s/g,'').replace(/^\+/,'');
 var brackets = /\([^\(\)]*\)/;
 var exp = s.match(brackets);
 while (exp = s.match(brackets)) s = s.replace(exp[0], evalExp0(exp[0])); //скобки
 return evalExp0(s);
 
 function evalExp0(s) {
  s = s.replace(/[\(\)]/g,'');
  var multOrDivExpr = /\d+\.?\d*\s*[\*\/]\s*[+-]?\d+\.?\d*/; //умножение и деление
  var multOp = /\*/;
  var addOrSubExpr = /-?\d+\.?\d*\s*[\+-]\s*[+-]?\d+\.?\d*/; //сложение и вычитание
  var addOp  = /\d\+/;
  var exp;
 
  while (exp = s.match(multOrDivExpr)) {
   s = exp[0].match(multOp) ? s.replace(exp[0], multiply(exp[0])) : s.replace(exp[0], divide(exp[0]));
  }
  while (exp = s.match(addOrSubExpr)) {
   s = exp[0].match(addOp)? s.replace(exp[0], add(exp[0])) : s.replace(exp[0], subtract(exp[0]));
  }
  return '' + s;
 
  function multiply(s, b) { b = s.split('*'); return b[0] * b[1]; }

  function divide (s, b) { b = s.split('/'); return b[0] / b[1]; }
 
  function add (s, b) { 
   s = s.replace(/^\+/,'').replace(/\++/,'+'); 
   b = s.split('+'); 
   return Number(b[0]) + Number(b[1]); 
  }
 
  function subtract(s, b) {
   s = s.replace(/\+-|-\+/g,'-');
   if (s.match(/--/)) return add(s.replace(/--/,'+')); //два минуса == плюсу
   b = s.split('-');
   return b.length == 3? -1 * b[1] - b[2] : b[0] - b[1];
  }
 }
}
</script>
<noscript><div align="center">Сервис недоступен из-за отключённого Javascript в браузере</div></noscript>
<div align="center">
 <form>
  <input type="text" size="60" maxlength="58" 
   onkeyup="document.getElementById('result').innerHTML=evalExp(this.value);">
 </form>
 <div id="result"></div>
</div>

14.09.2017, 12:29 [2382 просмотра]


теги: числа javascript сервис математика

К этой статье пока нет комментариев, Ваш будет первым