【发布时间】:2014-01-03 12:30:40
【问题描述】:
我必须处理已经存在的自定义标记语言(这很丑陋,但不幸的是无法更改,因为我正在处理旧数据并且它需要与旧应用保持兼容)。
我需要解析命令“范围”,并根据用户采取的操作将数据中的这些“范围”替换为其他内容(HTML 或 LaTeX 代码)或从输入中完全删除这些“范围”。
我目前的解决方案是在循环中使用preg_replace_callback(),直到没有匹配项为止,但对于大型文档来说它非常慢。 (即 57 KB 文档中 394 次替换大约需要 7 秒)
递归正则表达式对于这项任务似乎不够灵活,因为我需要访问所有匹配项,即使在递归中也是如此。
问题:如何提高解析性能?
正则表达式可能会被完全删除——它们不是必需的,但我唯一能想到的。
注意:下面的代码示例已大大减少。 (SSCCE)实际上有许多不同的“类型”范围,闭包函数根据操作模式做不同的事情。 (从 DB 中插入值、删除整个范围、转换为另一种格式等。)请记住这一点!
我目前正在做的示例:
<?php
$data = <<<EOF
some text 1
begin-command
some text 2
begin-command
some text 3
command-end
some text 4
begin-command-if "%VAR%" == "value"
some text 5
begin-command
some text 6
command-end
command-end
command-end
EOF;
$regex = '~
# opening tag
begin-(?P<type>command(?:-if)?)
# must not contain a nested "command" or "command-if" command!
(?!.*begin-command(?:-if)?.*command(?:-if)?-end)
# the parameters for "command-if" are optional
(?:
[\s\n]*?
(?:")[\s\n]*(?P<leftvalue>[^\\\\]*?)[\s\n]*(?:")
[\s\n]*
# the operator is optional
(?P<operator>[=<>!]*)
[\s\n]*
(?:")[\s\n]*(?P<rightvalue>[^\\\\]*?)[\s\n]*(?:")
[\s\n]*?
)?
# the real content
(?P<content>.*?)
# closing tag
command(?:-if)?-end
~smx';
$counter = 0;
$loop_replace = true;
while ($loop_replace) {
$data = preg_replace_callback($regex, function ($matches) use ($counter) {
global $counter;
$counter++;
return "<command id='{$counter}'>{$matches['content']}</command>";
}, $data, -1, $loop_replace);
}
echo $data;
【问题讨论】:
-
提高性能(明显)很可能意味着使用纯字符串操作,而不是正则表达式。
-
@BartKiers 完全同意。但是,考虑到文档结构(嵌套)的复杂性和要执行的不同任务,如何处理?这就是为什么我问这个问题,实际上。我不知道如何继续最好。