在PHP中标记CSS的性能

这是一个从未编写过解析器/词法分析器的人的noob问题.

我正在用PHP编写CSS的标记器/解析器(请不要重复’OMG,为什么用PHP?’).语法由W3C整齐地记录下来here (CSS2.1)here (CSS3, draft).

它是21个可能令牌的列表,所有(但是两个)都不能表示为静态字符串.

我当前的方法是一遍又一遍地循环包含21个模式的数组,执行if(preg_match())并通过匹配减少源字符串匹配.原则上这非常好.但是,对于1000行的CSS字符串,这需要2到8秒的时间,这对我的项目来说太多了.

现在我正在敲打我的脑袋,其他解析器如何标记化并在几秒钟内解析CSS.好吧,C总是比PHP快,但是,有没有明显的D’哦!我陷入了什么?

我做了一些优化,比如检查’@’,’#’或’“’作为剩余字符串的第一个字符,然后仅应用相关的正则表达式,但这并未带来任何出色的性能提升.

到目前为止我的代码(片段):

$TOKENS = array(
  'IDENT' => '...regexp...',
  'ATKEYWORD' => '@...regexp...',
  'String' => '"...regexp..."|\'...regexp...\'',
  //...
);

$string = '...CSS source string...';
$stream = array();

// we reduce $string token by token
while ($string != '') {
    $string = ltrim($string, " \t\r\n\f"); // unconsumed whitespace at the
        // start is insignificant but doing a trim reduces exec time by 25%
    $matches = array();
    // loop through all possible tokens
    foreach ($TOKENS as $t => $p) {
        // The '&' is used as delimiter, because it isn't used anywhere in
        // the token regexps
        if (preg_match('&^'.$p.'&Su', $string, $matches)) {
            $stream[] = array($t, $matches[0]);
            $string = substr($string, strlen($matches[0]));
            // Yay! We found one that matches!
            continue 2;
        }
    }
    // if we come here, we have a syntax error and handle it somehow
}

// result: an array $stream consisting of arrays with
// 0 => type of token
// 1 => token content

解决方法:

使用lexer generator.

上一篇:是否有JavaScript词法分析器/令牌生成器(在PHP中)?


下一篇:谁能推荐一种使用C#执行以下字符串操作的方法