亲爱的程序员您好!我遇到了函数速度问题
preg_replace()
。
当我在 $patterns
和 $replacements
数组中有
little值(
words)时,问题不在于从数组中搜索和替换 in text 的 speed,并且当数组中的值增加了 1.000.000,然后函数
preg_replace()
重复地变慢。如果数组中的值(单词)超过 1,000,000 个,如何在文本中搜索和替换?如何尽可能快速更换?问题的解决方案可以是buffered还是cached吗?有什么建议,我该如何正确行事?
这是我的数组的示例:
$patterns =
array
(
0 => "/\bмувосокори\b/u",
1 => "/\bмунаггас\b/u",
2 => "/\bмангит\b/u",
3 => "/\bмангития\b/u",
4 => "/\bмунфачир\b/u",
5 => "/\bмунфачира\b/u",
6 => "/\bманфиатпарасти\b/u",
7 => "/\bманфиатчу\b/u",
8 => "/\bманфиатчуи\b/u",
9 => "/\bманфиатхох\b/u",
10 => "/\bманфи\b/u",
...........................
1000000 => "/\bмусби\b/u"
)
$replacements =
array
(
0 => "мувосокорӣ",
1 => "мунағғас",
2 => "манғит",
3 => "манғития",
4 => "мунфаҷир",
5 => "мунфаҷира",
6 => "манфиатпарастӣ",
7 => "манфиатҷӯ",
8 => "манфиатҷӯӣ",
9 => "манфиатхоҳ",
10 => "манфӣ",
.....................
1000000 => "мусбӣ"
);
$text = "мувосокори мунаггас мангит мангития мунфачир манфиатпарасти...";
$result = preg_replace($patterns, $replacements, $text);
我在index.html文件中使用这个javascript函数:
<script>
function response(str) {
if (str.length == 0) {
document.getElementById("text").innerHTML = "";
return;
} else {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("text").innerHTML = this.responseText;
}
};
xmlhttp.open("GET", "response.php?request=" + str, true);
xmlhttp.send();
}
}
</script>
PHP 文件response.php 来源:
<?php
$patterns = array();
$replacements = array();
$request = $_REQUEST["request"];
$response = "";
if ($request !== "") {
$start = microtime(true);
$response = preg_replace($patterns, $replacements, $request);
$stop = microtime(true);
$time_replace = $stop - $start;
}
echo $response === "" ? "" : $response."<br>Time: $time_replace";
?>
算法的时间复杂度大致为 O(nm),其中 n 是替换数组中的单词数,m 是请求中的单词数。
由于所有模式似乎都在查找单词(前后
\b
),并且不使用任何其他正则表达式语法(仅文字字符),因此通过将请求拆分为单词并在其中查找它们,您将获得更好的性能关联数组,根本不需要使用正则表达式。
因此将模式/替换数据定义为关联数组,如下所示:
$dict = array(
"мувосокори" => "мувосокорӣ",
"мунаггас" => "мунағғас",
"мангит" => "манғит",
"мангития" => "манғития",
"мунфачир" => "мунфаҷир",
"мунфачира" => "мунфаҷира",
"манфиатпарасти" => "манфиатпарастӣ",
"манфиатчу" => "манфиатҷӯ",
"манфиатчуи" => "манфиатҷӯӣ",
"манфиатхох" => "манфиатхоҳ",
"манфи" => "манфӣ",
...........................
"мусби" => "мусбӣ"
);
然后使用
preg_replace_callback
查找请求中的每个单词并在上面的词典中查找:
$response = preg_replace_callback("/\pL+/u", function ($m) use ($dict) {
return isset($dict[$m[0]]) ? $dict[$m[0]] : $m[0];
}, $request);
时间复杂度与请求中的单词数成线性关系。
如果您还需要匹配单词大小写的任何变化,那么在字典中存储任何此类变化就太多了。相反,您可以将字典保留为全部小写字母,然后使用下面的代码。当与字典匹配时,它会检查原始单词的大小写,并将相同的内容应用于替换单词:
$response = preg_replace_callback("/\pL+/u", function ($m) use ($dict) {
$word = mb_strtolower($m[0]);
if (isset($dict[$word])) {
$repl = $dict[$word];
// Check for some common ways of upper/lower case
// 1. all lower case
if ($word === $m[0]) return $repl;
// 2. all upper case
if (mb_strtoupper($word) === $m[0]) return mb_strtoupper($repl);
// 3. Only first letters are upper case
if (mb_convert_case($word, MB_CASE_TITLE) === $m[0]) return mb_convert_case($repl, MB_CASE_TITLE);
// Otherwise: check each character whether it should be upper or lower case
for ($i = 0, $len = mb_strlen($word); $i < $len; ++$i) {
$mixed[] = mb_substr($word, $i, 1) === mb_substr($m[0], $i, 1)
? mb_substr($repl, $i, 1)
: mb_strtoupper(mb_substr($repl, $i, 1));
}
return implode("", $mixed);
}
return $m[0]; // Nothing changes
}, $request);
您可以使用一小段代码将当前的 $patterns 和 $replacements 数组转换为新的数据结构,以避免您必须“手动”执行此操作:
foreach ($patterns as $i => $pattern) {
$dict[explode("\b", $pattern)[1]] = $replacements[$i];
}
当然,您不应该在代码中包含此转换,而只需运行一次以生成新的数组结构,然后将该数组文字放入代码中。