Как ввести 2^3 в Math.pow(2, 3)?

У меня есть этот простой скрипт калькулятора, но он не позволяет мощность ^.

function getValues() {
    var input = document.getElementById('value').value;

    document.getElementById('result').innerHTML = eval(input);

}
<label for="value">Enter: </label><input id="value">

  <div id="result">Results</div>

  <button onclick="getValues()">Get Results</button>

Я пытался использовать input = input.replace( '^', 'Math.pow(,)');

Но я не знаю, как получить значения до '^' и после в скобки.

Пример: (1+2)^3^3 должно дать 7 625 597 484 987.


person Community    schedule 09.02.2017    source источник
comment
Простой случай, когда это просто x^y, где x,y — целые числа, вполне выполним с помощью простого регулярного выражения. Однако правильно разобрать что-то вроде (2+34)^5, очевидно, сложнее. Не могли бы вы уточнить, что вы хотите сделать?   -  person CollinD    schedule 10.02.2017
comment
см.: основы написания оценки выражения   -  person Spektre    schedule 10.02.2017


Ответы (6)


Используйте регулярное выражение с группами захвата:

input = '3 + 2 ^3';
input = input.replace(/(\d+)\s*\^\s*(\d+)/g, 'Math.pow($1, $2)');
console.log(input);

Это будет работать только тогда, когда аргументы являются просто числами. Это не будет работать с подвыражениями или когда вы повторяете его, например

(1+2)^3^3

Это потребует написания синтаксического анализатора рекурсивного спуска, и это гораздо больше работы, чем я готов вложить в ответ здесь. Получите учебник по дизайну компилятора, чтобы узнать, как это сделать.

person Barmar    schedule 09.02.2017
comment
Это идеальное решение, поскольку оно позволяет использовать выражения с несколькими операциями. - person AmericanUmlaut; 10.02.2017

Я не думаю, что вы сможете сделать это с помощью простой замены.

Если вы хотите анализировать инфиксные операторы, вы создаете два стека: один для символов, другой для чисел. Затем последовательно пройтись по формуле, игнорируя все остальное, кроме символов, цифр и закрывающей скобки. Поместите символы и числа в их стопки, но когда вы встретите закрывающую скобку, возьмите последний символ и примените его к двум последним числам. (был изобретен Дейкстрой, я думаю)

const formula = '(1+2)^3^3'


const symbols = []
const numbers = []

function apply(n2, n1, s) {
  if (s === '^') {
    return Math.pow(parseInt(n1, 10), parseInt(n2, 10))
  }
 
  return eval(`${n1} ${s} ${n2}`)
}

const applyLast = () => apply(numbers.pop(), numbers.pop(), symbols.pop())

const tokenize = formula => formula.split(/(\d+)|([\^\/\)\(+\-\*])/).filter(t => t !== undefined && t !== '')

const solver = (formula) => {
  const tf = tokenize(formula)

  for (let l of formula) {
    const parsedL = parseInt(l, 10)
    if (isNaN(parsedL)) {
      if (l === ')') {
        numbers.push(applyLast())
        continue
      } else {
        if (~['+', '-', '*', '/', '^'].indexOf(l))
          symbols.push(l)
        continue
      }
      
    } 
    numbers.push(l)
  }
  
  while (symbols.length > 0)
    numbers.push(applyLast())
  
  return numbers.pop()
}

console.log(solver(formula))

person rdkn    schedule 10.02.2017

Получите свой ввод в строку и выполните...

var input = document.getElementById('value').value;
var values = input.split('^'); //will save an array with [value1, value 2]
var result = Math.pow(values[0], values[1]);
console.log(result);

Это только в том случае, если ваша единственная операция - '^'

EDIT: видел пример после редактирования, это больше не работает.

person Alan    schedule 09.02.2017

function getValues() {
    var input = document.getElementById('value').value;

    // code to make ^ work like Math.pow
    input = input.replace( '^', '**');

    document.getElementById('result').innerHTML = eval(input);

}

Оператор ** может заменить функцию Math.pow в большинстве современных браузеров. Следующая версия Safari (v10.1), которая выйдет со дня на день, поддерживает его.

person at.    schedule 10.02.2017

Как сказано в других ответах здесь, вам нужен настоящий парсер, чтобы решить это правильно. Регулярное выражение решит простые случаи, но для вложенных операторов вам нужен рекурсивный синтаксический анализатор. Для Javascript одна библиотека, которая предлагает это, — peg.js.

В вашем случае пример, приведенный в онлайн-версии, можно быстро расширить для обработки полномочий:

Expression
  = head:Term tail:(_ ("+" / "-") _ Term)* {
      var result = head, i;

      for (i = 0; i < tail.length; i++) {
        if (tail[i][1] === "+") { result += tail[i][3]; }
        if (tail[i][1] === "-") { result -= tail[i][3]; }
      }

      return result;
    }

Term
  = head:Pow tail:(_ ("*" / "/") _ Pow)* { // Here I replaced Factor with Pow
      var result = head, i;

      for (i = 0; i < tail.length; i++) {
        if (tail[i][1] === "*") { result *= tail[i][3]; }
        if (tail[i][1] === "/") { result /= tail[i][3]; }
      }

      return result;
    }

// This is the new part I added
Pow
  = head:Factor tail:(_ "^" _ Factor)* {
      var result = 1;
      for (var i = tail.length - 1; 0 <= i; i--) {
          result = Math.pow(tail[i][3], result);
      }
      return Math.pow(head, result);
    }

Factor
  = "(" _ expr:Expression _ ")" { return expr; }
  / Integer

Integer "integer"
  = [0-9]+ { return parseInt(text(), 10); }

_ "whitespace"
  = [ \t\n\r]*

Он возвращает ожидаемый результат 7625597484987 для входной строки (1+2)^3^3.

person fafl    schedule 10.02.2017

Вот версия этого вопроса на основе Python с решением, использующим pyparsing: ">изменение оператора ** на силовую функцию с помощью синтаксического анализа?

person PaulMcG    schedule 23.03.2017