如何在 $patterns 和 $replacements 数组中使用具有大量 (1000000) 个值的函数 preg_replace?
How to work with a function preg_replace with a large number (1000000) of values in $patterns and $replacements arrays?
亲爱的程序员,您好!我在函数 preg_replace()
.[=20] 的速度方面遇到 问题 =]
当我在 $patterns
和 $replacements
数组中有 little 值(words)时,问题不是用 speed 从数组中搜索和替换 in text,并且当数组 中的值的数量增加时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);
I use this javascript function in index.html file:
<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 file response.php source:
<?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
前后),并且不使用任何其他正则表达式语法(仅文字字符),您可以通过将请求拆分为更好的性能单词并在关联数组中查找它们,根本不需要使用正则表达式。
因此将您的 pattern/replacement 数据定义为关联数组,如下所示:
$dict = array(
"мувосокори" => "мувосокорӣ",
"мунаггас" => "мунағғас",
"мангит" => "манғит",
"мангития" => "манғития",
"мунфачир" => "мунфаҷир",
"мунфачира" => "мунфаҷира",
"манфиатпарасти" => "манфиатпарастӣ",
"манфиатчу" => "манфиатҷӯ",
"манфиатчуи" => "манфиатҷӯӣ",
"манфиатхох" => "манфиатхоҳ",
"манфи" => "манфӣ",
...........................
"мусби" => "мусбӣ"
);
然后用preg_replace_callback
找到request中的每一个词,在上面的字典中查找:
$response = preg_replace_callback("/\pL+/u", function ($m) use ($dict) {
return isset($dict[$m[0]]) ? $dict[$m[0]] : $m[0];
}, $request);
时间复杂度与请求中的字数成线性关系。
处理upper/lower个案
如果您还需要匹配单词大小写的任何变化,那么将任何此类变化存储在字典中就太多了。相反,您可以将字典全部保留为小写字母,然后使用下面的代码。当与字典匹配时,它会检查原始单词的大小写,并将其应用于替换单词:
$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);
在 repl.it
上查看 运行
正在转换现有数组
您可以使用一小段代码将当前的 $patterns 和 $replacements 数组转换为新的数据结构,以便避免你必须这样做 "manually":
foreach ($patterns as $i => $pattern) {
$dict[explode("\b", $pattern)[1]] = $replacements[$i];
}
当然,您不应该在您的代码中包含此转换,而只是 运行 它一次以生成新的数组结构,然后将该数组文字放入您的代码中。
亲爱的程序员,您好!我在函数 preg_replace()
.[=20] 的速度方面遇到 问题 =]
当我在 $patterns
和 $replacements
数组中有 little 值(words)时,问题不是用 speed 从数组中搜索和替换 in text,并且当数组 中的值的数量增加时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);
I use this javascript function in index.html file:
<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 file response.php source:
<?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
前后),并且不使用任何其他正则表达式语法(仅文字字符),您可以通过将请求拆分为更好的性能单词并在关联数组中查找它们,根本不需要使用正则表达式。
因此将您的 pattern/replacement 数据定义为关联数组,如下所示:
$dict = array(
"мувосокори" => "мувосокорӣ",
"мунаггас" => "мунағғас",
"мангит" => "манғит",
"мангития" => "манғития",
"мунфачир" => "мунфаҷир",
"мунфачира" => "мунфаҷира",
"манфиатпарасти" => "манфиатпарастӣ",
"манфиатчу" => "манфиатҷӯ",
"манфиатчуи" => "манфиатҷӯӣ",
"манфиатхох" => "манфиатхоҳ",
"манфи" => "манфӣ",
...........................
"мусби" => "мусбӣ"
);
然后用preg_replace_callback
找到request中的每一个词,在上面的字典中查找:
$response = preg_replace_callback("/\pL+/u", function ($m) use ($dict) {
return isset($dict[$m[0]]) ? $dict[$m[0]] : $m[0];
}, $request);
时间复杂度与请求中的字数成线性关系。
处理upper/lower个案
如果您还需要匹配单词大小写的任何变化,那么将任何此类变化存储在字典中就太多了。相反,您可以将字典全部保留为小写字母,然后使用下面的代码。当与字典匹配时,它会检查原始单词的大小写,并将其应用于替换单词:
$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);
在 repl.it
上查看 运行正在转换现有数组
您可以使用一小段代码将当前的 $patterns 和 $replacements 数组转换为新的数据结构,以便避免你必须这样做 "manually":
foreach ($patterns as $i => $pattern) {
$dict[explode("\b", $pattern)[1]] = $replacements[$i];
}
当然,您不应该在您的代码中包含此转换,而只是 运行 它一次以生成新的数组结构,然后将该数组文字放入您的代码中。