freezewarp/php-shunting-yard

灵活的Shunting Yard解析器,基于https://github.com/andig/php-shunting-yard

1.2.1 2019-07-26 05:05 UTC

This package is auto-updated.

Last update: 2024-09-17 12:26:08 UTC


README

分支更改

此分支的一般目标是采用现有的安全公式评估框架,并添加更多通用输入所需的功能(而原始版本主要侧重于数字)。

为此,进行了以下更改

  • 常量可以是任何PHP值,不仅仅是数值。(内部表示为T_NATIVE,并包含T_NULL。)

  • 已添加对字符串字面量的支持。

    • 添加了||运算符用于连接。 (此运算符的优先级高于相等但低于加法和减法。因此,2 + 3 || 3 + 4 = "57"。)
    • +运算符在任一边是非数值时充当连接运算符。(因此,"2" + "3" = 5,但"2 " + "3" = "2 3"。)
    • 支持字符串字面量,可以是"string"'string'。(不支持转义。)
  • 已添加对数组字面量的支持。

    • 如果任一操作数是数组,则||运算符将执行数组合并。
    • 可以使用in运算符检查数组成员的存在。还需要添加一个not in运算符。
    • 实现了列表和关联数组。列表使用语法[1, 2, 3],而关联数组使用语法[1 -> 2, 3 -> 4, 5 -> 6]
    • 数组键和值支持除shunting表达式外所有支持的运算——例如,[1 + 2 -> 3 + 4, 5 + 6 -> 7 + 8]等价于[3 -> 7, 11 -> 15]
  • 已扩展变量名

    • 现在,任何匹配/\p{L}\p{N}\.]+/(即只包含Unicode字母、数字和符号.)的字符串都将被视为变量名。这意味着littérature + 手紙是一个有效的公式,添加了两个变量。
    • 为更复杂的变量引用分配了特殊语法,${xyz}——这支持变量名中除}之外的任何字符。
    • 未注册的变量将评估为0而不是抛出异常。可以在上下文中设置一个严格的模式标志来重新启用旧的行为。
  • 使用#支持行尾注释

  • 进行了一些更具有主观性的更改,以使整体语法更友好

    • 没有设置默认常量。在构建时,可以传递一个数组以一次性设置所有常量。
    • andornot现在是&|!的别名。
    • ifcoalesceminmax函数默认注册。
    • 移除了xor运算符以避免可能的混淆(它曾是><)。

为所有这些更改编写了单元测试。所有现有和新测试都通过。

最后,虽然不包括在内,但个人推荐通过以下方式重载上下文来使用此包

new class($array) extends Context
{
    public function cs($name) {
        return your_array_getter($this->constants, $name);
    }
}

虽然默认类仅执行正常数组查找,但有许多进行更高级数组查找的机会。Laravel的array_get提供了基本的点查找,或者可以使用https://github.com/Galbar/JsonPath-PHP进行完整的JSONPath查找。

示例

简单的方程式解析

use RR\Shunt\Parser;

$equation = '3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3';
$result = Parser::parse($equation);
echo $result; //3.0001220703125

具有常量和函数的方程式

use RR\Shunt\Parser;
use RR\Shunt\Context;

$ctx = new Context();
$ctx->def('abs'); // wrapper for PHP "abs" function
$ctx->def('foo', 5); // constant "foo" with value "5"
$ctx->def('bar', function($a, $b) { return $a * $b; }); // define function

$equation = '3 + bar(4, 2) / (abs(-1) - foo) ^ 2 ^ 3';
$result = Parser::parse($equation, $ctx);
echo $result; //3.0001220703125

测试条件

use RR\Shunt\Parser;
use RR\Shunt\Context;

$ctx = new Context();
$ctx->def('foo', 5); // constant "foo" with value "5"

$equation = '(foo > 3) & (foo < 6)';
$result = Parser::parse($equation, $ctx);
echo $result; //true

在多个输入上重新运行解析表达式

use RR\Shunt\Parser;
use RR\Shunt\Context;

$counter = 1;
$ctx = new Context();
$ctx->def('data', function() { global $counter; return $counter++; }); // define function
$ctx->def('bar', function($a) { return 2*$a; }); // define function

$equation = 'bar(data())';
$parser = new Parser(new Scanner($equation));

$result = $parser->reduce($this->ctx); // first result
echo $result; // 2
$result = $parser->reduce($this->ctx); // second result
echo $result; // 4

安装

在您的composer.json文件中定义以下需求

{
    "require": {
        "freezewarp/php-shunting-yard": "dev-master"
    }
}

作者

这是一个基于 https://github.com/andig/php-shunting-yard 的分支,它又使用了以下代码: