代码之家  ›  专栏  ›  技术社区  ›  James McMahon

标记字符串、保留分隔符(PHP)的标准算法

  •  2
  • James McMahon  · 技术社区  · 16 年前

    我想把一个算术表达式分解成令牌,把它转换成RPN。

    Java具有StruttoKeNisher,它可以选择性地保留分隔符。这样,我可以使用操作符作为分隔符。不幸的是,我需要在具有strtok的php中完成这项工作,但这会丢弃分隔符,所以我需要自己做点什么。

    这听起来像是编译器设计101的经典教科书例子,但恐怕我这里缺乏一些正规的教育。你能给我指一个标准的算法吗?

    我的其他选择是 Lexical Analysis 或者用可用的字符串函数快速地卷起一些东西。

    3 回复  |  直到 16 年前
        1
  •  1
  •   PhiLho    16 年前

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

    $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)。

        2
  •  2
  •   Shoan    16 年前

    这可能会有所帮助。

    Practical Uses of Tokenizer

        3
  •  0
  •   James McMahon    16 年前

    好的,多亏了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;
    }