ребята, помогите пожалуйста, надо написать калькулятор выражений типа: 3+4-8/2 т.е. в input вводиться это выражение, нажимаю на submit и оно считается. только есть одно но: не использовать eval я новичок, только пытаюсь освоить php и этот калькулятор нужен в учебных целях =) спасибо всем, кто ответит. )
ну раз в учебных целях, то читайте один из методов разбора а можете и сами проанализировать задачу и написать простейший парсер выражений. вспоминайте про приоритет операций, скобки... и вперед. сложного ничего нет
а как прописать приоритет операций? и учесть скобки? пока получилась так: Код (Text): $exp=$_POST['expression']; function convert($exp){ //преобразую из инфиксной нотации в ОПН $expArr=preg_split('#([+\-*/\^()]|\d+)#', $exp, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); //разбить строку на символы $stack0=array(); //стэк $exit=array(); // выходная строка foreach($expArr as $exp0){ if( is_numeric($exp0)){ $exit[]=$exp0; } elseif (in_array($exp0, array('*','/','+','-'))) { $stack0[]=$exp0; } } $exprArray=array_merge($exit, $stack0); $expr=implode(" ", $exprArray); return $expr; } echo 'RESULT='.convert($exp); Добавлено спустя 1 минуту 5 секунд: это только перевод из инфиксной записи в польскую обратную нотацию =)
Хочешь научиться программировать или сайты на php делать? Если программировать бери другой язык, если сайты пиши на php сайт.
Препод мучает? А обязательно в такой записи 3+4-8/2? Добавлено спустя 19 секунд: Нельзя допустим задать какой то стандарт, допустим между числами должен быть пробел на пр. 3 + 4 - 8 / 2 + (2 - 3) думаю так парсить проще будет... эх что то фантазия сегодня у меня разыгралась
так уже сделала =) осталось приоритеты и скобки =( Код (Text): <?php $exp=$_POST['expression']; function convert($exp){ //преобразую из инфиксной нотации в ОПН $expArr=preg_split('#([+\-*/\^()]|\d+)#', $exp, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); //разбить строку на символы $stack0=array(); //стэк $exit=array(); // выходная строка foreach($expArr as $exp0){ if( is_numeric($exp0)){ $exit[]=$exp0; } elseif (in_array($exp0, array('*','/','+','-','('))) { $stack0[]=$exp0; } if (in_array($exp0, ')')){ // непонятное действие со скобками while (array_pop($exp0)!='('){ $exit[]=array_pop($exp0); } } } $exprArray=array_merge($exit, $stack0); $expr=implode(" ", $exprArray); return $expr; } echo 'RESULT='.convert($exp); // switch ($stack0) { // пытаюсь расставить приоритеты // case '+' and '-': return 1; break; // case '*' and '/': return 2; break; // case '^': return 3; break; // } function calc($str){ //считаю само выражение в ОПН $stack = array(); $token = strtok($str, ' '); while ($token !== false){ if (in_array($token, array('*', '/', '+', '-'))){ $b = array_pop($stack); $a = array_pop($stack); switch ($token){ case '*': $res = $a*$b; break; case '/': $res = $a/$b; break; case '+': $res = $a+$b; break; case '-': $res = $a-$b; break; } array_push($stack, $res); } elseif (is_numeric($token)){ array_push($stack, $token); } $token = strtok(' '); } return array_pop($stack); } $str=convert($exp); echo calc($str); ?> Добавлено спустя 2 минуты 25 секунд: вот в первой функции переводим из нормальной записи в польскую обратную, во второй функции считаем =) про счет у меня почти все правильно, осталось только "^" добавить... а про перевод ступарюсь с приоритетами и скобками... =( не знаю даже как алгоритм с приоритетами сделать да и чем =(
А он точно у тебя работает? Я вот запустил и вижу Warning: in_array() expects parameter 2 to be array, string given
не работает из-за того, что начала скобки растовлять.... если их убрать, то будет работать, только не правильно( он из выражения 2+2*3 будет писать 223+*, а не 223*+ т.е. нет приоритетов у операторов =(
Я вернулся О а ты оказывается девушка, какой у тебя оригинальный ник... думал что парень Добавлено спустя 33 секунды: Мда, лень как то разбирать код, может пойти другим путем если парсить проблема. Не совсем эстетично но думаю проблема решиться, зачет поставят Попробуй регом Добавлено спустя 10 секунд: 1) вытащить то что в скобках, и посчитать, результат в массив 2) preg_replace замени скобки на пр на ? 3) когда найдешь в строке ? по порядку вытаскиваем из массива данные ну и т.д. Добавлено спустя 39 секунд: может когда время будет предложу что то лучше
хмм... да просто неахото делать что-то другое, если здесь почти все сделано =) Добавлено спустя 2 минуты 16 секунд: девушка =) и пока не шарю в php ничего, как оказалось =(
igordata в обратной записи считать машина, под названием компьютер, может, а в нормальной (инфиксной) только evel можно применять... но у меня задача именно без него делать( кстати, вот что получилось при расставлении приоритетов... вроде работает, но что-то неправильно. переобозначение prev мне не нравиться=( и траблы в возведению в степень и скобками( Код (Text): $exp=$_POST['expression']; function convert($exp){ //преобразую из инфиксной нотации в ОПН $expArr=preg_split('#([+\-*/\^()]|\d+)#', $exp, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); //разбить строку на символы $stack0=array(); //стэк $exit=array(); // выходная строка $prev=''; foreach($expArr as $exp0){ //for ($i=0; $i<=count($expArr); $i++) if( is_numeric($exp0)){ $exit[]=$exp0; } elseif (in_array($exp0, array('*','/','+','-','('))) { if (prior($exp0)==1){ $stack0[]=$exp0; } elseif (prior($exp0)==2) { if (prior($prev)<2){ $stack0[]=$exp0; } else { $exit[]=$prev; array_pop($stack0); $stack0[]=$exp0; } } elseif (prior($exp0)==3) { if (prior($prev)<3){ $stack0[]=$exp0; } else { $exit[]=$prev; array_pop($stack0); $stack0[]=$exp0; } $prev=$exp0; } } // if (in_array($exp0, ')')){ // непонятное действие со скобками // while (array_pop($exp0)!='('){ // $exit[]=array_pop($exp0); // } // } } $exprArray=array_merge($exit, array_reverse($stack0)); $expr=implode(" ", $exprArray); return $expr; } echo 'RESULT='.convert($exp); function prior($stack0){ switch ($stack0) { // пытаюсь расставить приоритеты case '(': return 1; break; case '+' and '-': return 2; break; case '*' and '/': return 3; break; case '^': return 4; break; // case '^': return 4; break; default: return 0; } }
ну и корень тоже в траблы Добавлено спустя 1 минуту 34 секунды: igordata в этом разницы нет, я про польскую обратную запись) я по ней все делаю... а в твоем примере: от перемены мест слагаемых сумма не меняеться =)
там не совсем так. смысл такой чтобы перевести обычное выражение в выражение когда идет поток данных и операций между ними в порядке приоритета, в котором нужно вычислить это выражение. тогда его можно просто вычислить программно Добавлено спустя 2 минуты 32 секунды: Negaty Код (PHP): function convertToPolishNotation($s) { static $prior = array('^'=>3, '*'=>3, '/'=>3, '+'=>2, '-'=>2, '('=>1); $stack = $out = $items = array(); $pair = array(); // get operators & operands $d=null; for($i=0,$l=strlen($s); $i<$l; ++$i) { // scan expression if (is_numeric($s{$i}) || $s{$i}=='.') $d.=$s{$i}; else { if ($d!=null) { $out[]=$d; // add operand(numeric) $pair[] = $d; $d=null; } // add operator if (sizeof($stack) == 0 || $s{$i} == '(') { $stack[] = $s{$i}; } elseif ($s{$i} == ')') { for ($j=sizeof($stack)-1; $j>=0; --$j) { if ($stack[$j] != '(') $out[] = array_pop($stack); else{ array_pop($stack); break; } } } else { // + - * / for ($j = sizeof($stack)-1; $j>=0; --$j) { if ($prior[$stack[$j]] < $prior[$s{$i}]) break; $out[] = $stack[$j]; unset($stack[$j]); } $stack = array_values($stack); $stack[] = $s{$i}; } }// else } if ($d!=null) $out[]=$d; if (sizeof($stack)) $out = array_merge($out, array_reverse($stack)); return $out; }
потому что она противоположна "прямой польской нотации", где операторы идут слева от операндов. польская нотация позволяет избавится от скобок в выражении, среди всего прочего. а обратная польская запись - позволяет вычислить результат выражения используя более просто алгоритм и вообще ресурсы компа. тоесть проще делать ее разбор программно
Польская нотация (запись), также известна как префиксная нотация (запись), это форма записи логических, арифметических и алгебраических выражений. Характерная черта такой записи — оператор располагается слева от операндов. +34 Обра́тная по́льская нота́ция (ОПН) — форма записи математических выражений, в которой операнды расположены перед знаками операций. 34+