2016-09-19 4 views
0

Я создаю калькулятор, в котором я получаю строку из поля ввода. Эта строка может быть, например, 2+3*9/3-6.Regex для разделения арифметического выражения на части

Теперь я хочу выполнить операции умножения и деления сначала , поэтому я получу 2+ 9 -6, где 9 будет отвечать на операции более высокого приоритета.

До сих пор я это сделал. Это полная функция:

function calculateResult(){ 
    var higher = /(\d+[*\/]\d+)/g; 
    calstr = $('#input-display').val(); 
    var m = '*'; 
    var res = calstr.split(higher); 
    console.log(res.length+ ' : ' + res); 
    // console.log(res); 
    if(res.length > 2){ 
     console.log('split success'); 
     var index = 0; 
     do{ 
      for(var i = 1; i < res.length; i+=2){ 
       var a = res[i].split(/([0-9\.]+)/g); 
       console.log('before calculation : '+calstr); 
       var regex = RegExp('(?:.*?(\\d+[*\/]\\d+)){' + i + '}'); 
       console.log('regex generated : '+regex); 
       if(a[2] == '*'){ 
        calstr = calstr.replace(regex , Number(a[1])*Number(a[3])); 
       } 
       else if(a[2] == '/'){ 
        calstr = calstr.replace(regex , Number(a[1])/Number(a[3])); 
       } 
       console.log('replaced result : ' + calstr); 
       console.log('replaced result at : ' + calstr.search(regex)); 
      } 
      // console.log('result : ' + calstr); 
      console.log('multiplication complete'); 
      res = calstr.split(higher); 
      console.log('result is : '+res); 
     }while(res.length > 2); 
    } 
    else if(res.length == 1) 
     console.log('split failed'); 
} 

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

Что я сделал не так?

Если все еще что-то неясно, я рад дать разъяснения.

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

+0

Было бы лучше, если бы вы точечную более короткий код snipset, что на самом деле не удается. На стороне примечания, вам нужно выполнить синтаксический анализ выражения или просто вызвать eval (_your_string_)? [Link] (http://www.w3schools.com/jsref/jsref_eval.asp) –

+0

Это мало что нужно сделать с jQuery. Вы используете его только для ввода входной строки ('$ ('# input-display'). Val();'), что не имеет отношения к вопросу. – trincot

+0

См. Также http://stackoverflow.com/questions/32982719/chrome-app-doing-maths-from-a-string/ – guest271314

ответ

1

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

RegExp('(?:.*?(\\d+[*\/]\\d+)){' + i + '}'); 

Он не должен совпадать с .*?, так как это заставит вас удалить все предыдущие символы приведенный ниже replace.

Кроме того, не требуется \. Если вы действительно хотели избежать / для регулярного выражения, вам придется удвоить предыдущую обратную косую черту, поскольку она также должна быть экранирована в цитируемой строке. Но так как прямая косая черта не встречается в литерале регулярных выражений (например, /.../g), ее вовсе не нужно избегать.

Часть {' + i + '} не является полезной. Это требует только того, что шаблон происходит много раз, но это может быть неверным после того, как вы сделали уже несколько замен. На самом деле вам нужно каждый раз соответствовать первому вступлению, поскольку все предыдущие были уже заменены.

Так оно и должно быть только это:

RegExp('(\\d+[*/]\\d+)'); 

... и поэтому на самом деле ничем не отличается от higher регулярных выражений, для глобального модификатора за исключением. Но этот глобальный модификатор на higher не нужен, так как split все равно ищет все вхождения, даже без этого модификатора. Это означает, что вам действительно нужно только higher (без g), а не регулярное выражение выше.

Некоторые другие вещи, чтобы улучшить:

  1. Следующая отладка линии не очень полезны, потому что calstr уже изменен, в то время как регулярное выражение применялось до изменения:

    console.log('replaced result at : ' + calstr.search(regex)); 
    
  2. Лучше не обращаться к входному элементу input-display внутри функции. Вместо этого передайте calstr в качестве аргумента функции. Это делает его независимым от вашего контекста браузера.

  3. Number(...) можно сделать короче с унитарным плюсом (+).

Вот обновленный код, который также осуществляет обработку + и -, поместив все это в другом цикле, который имеет 3 итерации: один для * и /, а два других для - (которые должны прийти перед тем +!) и +. Это имело еще одну сложность: унитарный минус не следует путать с обычным оператором минус. Вы увидите, что это удалось с (?:^-)? во внутреннем регулярном выражении.

function calculateResult(calstr){ 
 
    for (var level = 0; level < 3; level++) { 
 
     var search = level == 0 ? '(\\d+[*/]\\d+)' 
 
        : level == 1 ? '(-?\\d+-\\d+)' 
 
           : '(-?\\d+\\+\\d+)'; 
 
     var higher = RegExp(search); 
 
     var res = calstr.split(higher); 
 
     while(res.length > 2){ 
 
      for(var i = 1; i < res.length; i+=2){ 
 
       var a = res[i].split(/((?:^-)?[0-9\.]+)/g); 
 
       calstr = calstr.replace(higher, 
 
        a[2] == '*' ? +a[1] * +a[3] 
 
        : a[2] == '/' ? +a[1]/+a[3] 
 
        : a[2] == '+' ? +a[1] + +a[3] 
 
           : +a[1] - +a[3] 
 
       ); 
 
      } 
 
      res = calstr.split(higher); 
 
     } 
 
    } 
 
    return res[0]; 
 
} 
 

 
$('button').click(function() { 
 
    var input = $('#input-display').val(); 
 
    var result = calculateResult(input); 
 
    $('span').text(result); 
 
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<input id="input-display" value="2+3*9/3-6"> 
 
<button>Calc</button><br> 
 
Result: <span></span>

Обратите внимание, что вы заново изобретать колесо, поскольку JavaScript предлагает функцию eval оценить (управляемые) выражения, как это. Более того, этот код не будет оценивать более сложные выражения, например, когда они имеют круглые скобки.

+0

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

+0

Добро пожаловать. Пожалуйста, обратите внимание на изменения, которые я сделал сейчас. Это касается части '{+ i +}': ее можно исключить. – trincot

0

Похоже первого регулярного выражения var higher = /(\d+[*\/]\d+)/g; не получение "3 * 9/3" от 2 + 3 * 9/3-6 (проверено) https://regex101.com/#javascript

Попробуйте изменить его на

var higher = /(\d[^\+\-]*)+/g; 
+0

в первой итерации он соответствует 3 * 9 и вычисляет результат ... который равен 27, а затем заменяет его, что даст «2 + 27/3 -6 "... следующая итерация найдет 27/3 и заменит его на 9 .... тогда у нас будет« 2 + 9-6 »... глобальный работает как я намерен ...но проблемы возникают, когда я пытаюсь заменить 27 на 3 * 9, а затем заменить 27/3 на 9 ... , он заменяет 0-на-occurance. все это ... я не могу решить это. У большинства внутренних циклов есть регулярное выражение, которое должно заменить n-ые события .. но оно не работает, как я намерен ... так что, если я не ошибаюсь. Проблема с внутренним регулярным выражением –

2

Не проще было бы просто оценить вход?

function doEval() { 
 
    try { 
 
    alert(eval(document.querySelector('input').value)); 
 
    } catch (error) { 
 
    alert('Invalid input: ' + error); 
 
    } 
 
}
<input type='text' value='1+(4-3)*10/5' /> 
 
<input type='button' onclick='doEval();' value='Eval' />

+0

это никогда не приходило мне в голову ... но он действительно решает проблему ... я был сконцентрирован на регулярном выражении ... но я помог мне улучшить свои навыки регулярного выражения ... еще раз спасибо .... всегда приятно иметь более 1 решения –

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