如何使用函数 preg_replace 来处理 $patterns 和 $replacements 数组中的大量(1000000)个值?

问题描述 投票:0回答:1

亲爱的程序员您好!我遇到了函数速度问题

preg_replace()

当我在 $patterns$replacements 数组中有

little
值(
words
)时,问题不在于从数组中搜索和替换 in textspeed,并且当数组中的值增加了 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";

?>
php arrays replace preg-replace large-data
1个回答
3
投票

算法的时间复杂度大致为 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];
}

当然,您不应该在代码中包含此转换,而只需运行一次以生成新的数组结构,然后将该数组文字放入代码中。

© www.soinside.com 2019 - 2024. All rights reserved.