栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

如何用PHP制作计算器?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

如何用PHP制作计算器?

根据您的需求,建议您使用Shunting Yard Algorithm。它很容易实现,并且效果很好。

这是将代码复制/粘贴到一个块中的代码:

表达式定义:

class Parenthesis extends Terminalexpression {    protected $precidence = 7;    public function operate(Stack $stack) {    }    public function getPrecidence() {        return $this->precidence;    }    public function isNoOp() {        return true;    }    public function isParenthesis() {        return true;    }    public function isOpen() {        return $this->value == '(';    }}class Number extends Terminalexpression {    public function operate(Stack $stack) {        return $this->value;    }}abstract class Operator extends Terminalexpression {    protected $precidence = 0;    protected $leftAssoc = true;    public function getPrecidence() {        return $this->precidence;    }    public function isLeftAssoc() {        return $this->leftAssoc;    }    public function isOperator() {        return true;    }}class Addition extends Operator {    protected $precidence = 4;    public function operate(Stack $stack) {        return $stack->pop()->operate($stack) + $stack->pop()->operate($stack);    }}class Subtraction extends Operator {    protected $precidence = 4;    public function operate(Stack $stack) {        $left = $stack->pop()->operate($stack);        $right = $stack->pop()->operate($stack);        return $right - $left;    }}class Multiplication extends Operator {    protected $precidence = 5;    public function operate(Stack $stack) {        return $stack->pop()->operate($stack) * $stack->pop()->operate($stack);    }}class Division extends Operator {    protected $precidence = 5;    public function operate(Stack $stack) {        $left = $stack->pop()->operate($stack);        $right = $stack->pop()->operate($stack);        return $right / $left;    }}class Power extends Operator {    protected $precidence=6;    public function operate(Stack $stack) {        $left = $stack->pop()->operate($stack);        $right = $stack->pop()->operate($stack);        return pow($right, $left);    }}abstract class Terminalexpression {    protected $value = '';    public function __construct($value) {        $this->value = $value;    }    public static function factory($value) {        if (is_object($value) && $value instanceof Terminalexpression) { return $value;        } elseif (is_numeric($value)) { return new Number($value);        } elseif ($value == '+') { return new Addition($value);        } elseif ($value == '-') { return new Subtraction($value);        } elseif ($value == '*') { return new Multiplication($value);        } elseif ($value == '/') { return new Division($value);        } elseif ($value == '^') { return new Power($value);        } elseif (in_array($value, array('(', ')'))) { return new Parenthesis($value);        }        throw new Exception('Undefined Value ' . $value);    }    abstract public function operate(Stack $stack);    public function isOperator() {        return false;    }    public function isParenthesis() {        return false;    }    public function isNoOp() {        return false;    }    public function render() {        return $this->value;    }}

堆栈(非常简单的实现):

class Stack {    protected $data = array();    public function push($element) {        $this->data[] = $element;    }    public function poke() {        return end($this->data);    }    public function pop() {        return array_pop($this->data);    }}

最后,执行者类:

class Math {    protected $variables = array();    public function evaluate($string) {        $stack = $this->parse($string);        return $this->run($stack);    }    public function parse($string) {        $tokens = $this->tokenize($string);        $output = new Stack();        $operators = new Stack();        foreach ($tokens as $token) { $token = $this->extractVariables($token); $expression = Terminalexpression::factory($token); if ($expression->isOperator()) {     $this->parseOperator($expression, $output, $operators); } elseif ($expression->isParenthesis()) {     $this->parseParenthesis($expression, $output, $operators); } else {     $output->push($expression); }        }        while (($op = $operators->pop())) { if ($op->isParenthesis()) {     throw new RuntimeException('Mismatched Parenthesis'); } $output->push($op);        }        return $output;    }    public function registerVariable($name, $value) {        $this->variables[$name] = $value;    }    public function run(Stack $stack) {        while (($operator = $stack->pop()) && $operator->isOperator()) { $value = $operator->operate($stack); if (!is_null($value)) {     $stack->push(Terminalexpression::factory($value)); }        }        return $operator ? $operator->render() : $this->render($stack);    }    protected function extractVariables($token) {        if ($token[0] == '$') { $key = substr($token, 1); return isset($this->variables[$key]) ? $this->variables[$key] : 0;        }        return $token;    }    protected function render(Stack $stack) {        $output = '';        while (($el = $stack->pop())) { $output .= $el->render();        }        if ($output) { return $output;        }        throw new RuntimeException('Could not render output');    }    protected function parseParenthesis(Terminalexpression $expression, Stack $output, Stack $operators) {        if ($expression->isOpen()) { $operators->push($expression);        } else { $clean = false; while (($end = $operators->pop())) {     if ($end->isParenthesis()) {         $clean = true;         break;     } else {         $output->push($end);     } } if (!$clean) {     throw new RuntimeException('Mismatched Parenthesis'); }        }    }    protected function parseOperator(Terminalexpression $expression, Stack $output, Stack $operators) {        $end = $operators->poke();        if (!$end) { $operators->push($expression);        } elseif ($end->isOperator()) { do {     if ($expression->isLeftAssoc() && $expression->getPrecidence() <= $end->getPrecidence()) {         $output->push($operators->pop());     } elseif (!$expression->isLeftAssoc() && $expression->getPrecidence() < $end->getPrecidence()) {         $output->push($operators->pop());     } else {         break;     } } while (($end = $operators->poke()) && $end->isOperator()); $operators->push($expression);        } else { $operators->push($expression);        }    }    protected function tokenize($string) {        $parts = preg_split('((d+|+|-|(|)|*|/)|s+)', $string, null, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);        $parts = array_map('trim', $parts);        return $parts;    }}

它通过首先标记输入(基于单词边界和标记)来工作。然后,它在其上运行Shunting
Yard算法,以将输入转换为RPN(反向波兰表示法)堆栈。然后,只需执行堆栈即可。这是一个简单的示例:

$math = new Math();$answer = $math->evaluate('(2 + 3) * 4');var_dump($answer);// int(20)$answer = $math->evaluate('1 + 2 * ((3 + 4) * 5 + 6)');var_dump($answer);// int(83)$answer = $math->evaluate('(1 + 2) * (3 + 4) * (5 + 6)');var_dump($answer);// int(231)$math->registerVariable('a', 4);$answer = $math->evaluate('($a + 3) * 4');var_dump($answer);// int(28)$math->registerVariable('a', 5);$answer = $math->evaluate('($a + $a) * 4');var_dump($answer);// int(40)

现在,此示例比您可能需要的复杂得多。原因是它还处理分组和运算符优先级。但这是运行算法的一个很好的例子,它不使用eval并支持变量…



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/465666.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号