2

我想将算术表达式拆分为标记,将其转换为 RPN。

Java 有 StringTokenizer,它可以选择保留分隔符。这样,我可以使用运算符作为分隔符。不幸的是,我需要在具有 strtok 的 PHP 中执行此操作,但这会丢弃分隔符,所以我需要自己酿造一些东西。

这听起来像是 Compiler Design 101 的经典教科书示例,但恐怕我在这里缺乏一些正规教育。您可以指出我的标准算法吗?

我的其他选择是阅读词法分析或使用可用的字符串函数快速汇总一些内容。

4

3 回答 3

2

这可能会有所帮助。

Tokenizer 的实际使用

于 2008-09-29T08:59:59.407 回答
1

通常,我只会使用正则表达式来执行此操作:

$expr = '(5*(7 + 2 * -9.3) - 8 )/ 11';
$tokens = preg_split('/([*\/^+-]+)\s*|([\d.]+)\s*/', $expr, -1,
        PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
$tts = print_r($tokens, true);
echo "<pre>x=$tts</pre>";

它需要更多的工作来接受具有指数的数字(如 -9.2e-8)。

于 2008-09-29T11:01:44.403 回答
0

好的,感谢 PhiLho,我的最终代码是这样的,如果有人需要的话。它甚至不是很脏。:-)

static function rgTokenize($s)
{
    $rg = array();

    // remove whitespace
    $s = preg_replace("/\s+/", '', $s);

    // split at numbers, identifiers, function names and operators
    $rg = preg_split('/([*\/^+\(\)-])|(#\d+)|([\d.]+)|(\w+)/', $s, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);

    // find right-associative '-' and put it as a sign onto the following number
    for ($ix = 0, $ixMax = count($rg); $ix < $ixMax; $ix++) {
        if ('-' == $rg[$ix]) {
            if (isset($rg[$ix - 1]) && self::fIsOperand($rg[$ix - 1])) {
                continue;
            } else if (isset($rg[$ix + 1]) && self::fIsOperand($rg[$ix + 1])) {
                $rg[$ix + 1] = $rg[$ix].$rg[$ix + 1];
                unset($rg[$ix]);
            } else {
                throw new Exception("Syntax error: Found right-associative '-' without operand");
            }
        }
    }
    $rg = array_values($rg);

    echo join(" ", $rg)."\n";

    return $rg;
}
于 2008-09-29T13:39:22.247 回答