Это вопрос новичка от того, кто никогда раньше не писал парсер / лексер.
Я пишу токенайзер / парсер для CSS в PHP (пожалуйста, не повторяйте «OMG, почему в PHP?»). Синтаксис записан W3C аккуратно здесь (CSS2.1) и здесь (CSS3, черновик) .
Это список из 21 возможных токенов, все (кроме двух) не могут быть представлены в виде статических строк.
Мой текущий подход состоит в том, чтобы циклически перебирать массив, содержащий 21 шаблон, делать if (preg_match())
и уменьшать совпадение исходной строки на соответствие. В принципе это работает действительно хорошо. Однако для строки CSS из 1000 строк это занимает от 2 до 8 секунд, что слишком много для моего проекта.
Теперь я ломаю голову над тем, как другие парсеры токенизируют и , анализируют CSS за доли секунды. Хорошо, C всегда всегда быстрее, чем PHP, но, тем не менее, есть ли очевидные D'Oh! s, в которые я попал?
Я произвел некоторые оптимизации, например, проверил '@', '#' или '"' в качестве первого символа оставшейся строки и затем применил только соответствующее регулярное выражение, но это не принесло существенного повышения производительности.
Мой код (фрагмент) пока:
$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