我想用PHP来计算简单的代数表达式,比如,8*(51)
,通过
注意:这是我到目前为止的想法,效率很低,但这是一个临时解决方案。只要在可能的情况下替换字符串:在我们的示例中,识别字符串
51
,并将其替换为6
。然后,再次循环,将(6)
替换为6
,再次循环,并将8*6
替换为48
。例如,用于乘法的代码应如下所示:
for ($a=1; $a < 1000; $a++) {
for ($b=1; $b < 1000; $b++) {
string_replace($a . '*' . $b, $a*$b, $string);
}
}
首先,我将剥离表达式中不应包含的任何输入(假设您只希望允许加、减、乘、除和无变量):
$expr = preg_replace('/[^0-9+*\/-]/', '', $expr);
然后,一旦我确信用户输入中没有危险,只需通过eval()传递它来计算表达式:
$result = eval("return $expr;");
不需要重新发明轮子。
编辑以纳入Kolink的更正。谢谢!
有一个名为bcparserhp的数学解析器类可能会引起人们的兴趣。
看起来使用起来相当简单,功能也相当强大。
来自其站点的示例代码:
$parser = new MathParser();
$parser->setVariable('X', 5);
$parser->setVariable('Y', 2);
$parser->setExpression('COS(X)+SIN(Y)/2');
echo $parser->getValue();
不幸的是,这是一种商业产品;我不知道这是否会阻止你使用它(我想这取决于价格和你的需求)。
非商业性的替代方案可能是:http://www.phpclasses.org/package/2695-PHP-Safely-evaluate-mathematical-expressions.html
注意,这个类在内部使用eval()
,如果可能的话,我会避免这样做。
如果做不到这一点,编写自己的语言解析器将是理想的解决方案,但在PHP中这样做并不明智。
根据您的需要,我建议您研究调车场算法。它很容易实现,并且工作得很好。
我刚才举了一个例子:GIST。
以下是复制/粘贴到一个块中的代码:
表达式定义:
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);
}
}
最后是executor类:
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;
}
}
它的工作原理是首先标记输入(基于单词边界和标记)。然后,它在上面运行分流码算法,将输入转换成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且支持变量的运行算法的好例子。。。
问题内容: 我想使用PHP来计算普通用户通过标记输入的简单代数表达式,例如,(这意味着 常规符号 :不会像那样更改语法。此外,它必须显示所有步骤,但这并不难。问题是,现在,正在计算表达式的值。 注意:这是我到目前为止的想法,虽然效率很低,但这是临时的解决方案。只要可能就替换字符串:在我们的示例中,识别该字符串并将其替换为。然后,再次循环,替换为,再次循环,然后替换为。例如,用于乘法的代码应如下所示
我试过用 如何在php中计算crc16 CRC16函数的C到PHP转换 我在寻找校验和
我有两个XML EditTexts。在一个EditText中,用户可以将一个数字作为分钟,在另一个EditText中,可以将一个数字作为秒。单击finish按钮后,seconds EditText应开始倒计时,并每秒更新其文本。 此外,我如何保持更新,直到它达到零分钟零秒?
问题内容: 请查看以下代码: 这将显示11。 但!如果在功能参数中删除“&”运算符,则结果将为10。 这是怎么回事? 问题答案: 该运营商告诉PHP不要把它传递给函数时数组复制。取而代之的是,将对数组的 引用 传递给函数,因此函数修改了原始数组而不是副本。 只要看这个最小的例子: 在这里,输出为: –的呼叫未修改。另一方面,打到了。
我试图找到一种方法来擦除文本屏幕从我的计算器,当你按下 /-按钮,使其行为更像一个真正的计算器。 php文件返回html代码,其中我有一个
本文向大家介绍原生JavaScript制作计算器,包括了原生JavaScript制作计算器的使用技巧和注意事项,需要的朋友参考一下 原生JavaScript制作计算器 再给大家分享一个稍微复杂些的计算器 效果图演示