如何用特定字母替换特定数字(在长度限制内)?

How to replace specific numbers (within a length limit) with specific letters?

我正在尝试使用 preg_replace 将数字更改为字母,但只有 "" 中包含的数字且子字符串中的字符不超过 7 个。

示例输入字符串:

"3"sca"""co"1"str"0"ctor""r"3"t"0"r"1""locat"5"o"133""0"27""754a49b393c2a0"33"b97"332"cb7"3"c3c07"2""co"1"str"0"ctor""r"3"t"0"

期望的效果是每个符合条件的 2 变成 d,每个符合条件的 3 变成 e

这些是正确替换的示例:

我的编码尝试:

$string = preg_replace("/\"322\"+/", "edd", $string);
$string = preg_replace("/\"233\"+/", "dee", $string);
$string = preg_replace("/\"32\"+/", "ed", $string);
$string = preg_replace("/\"23\"+/", "de", $string);
$string = preg_replace("/\"33\"+/", "e", $string);
$string = preg_replace("/\"333\"+/", "e", $string);
$string = preg_replace("/\"3\"+/", "e", $string);
$string = preg_replace("/\"3\"+/", "e", $string);
$string = preg_replace("/\"3\"+/", "e", $string);
$string = preg_replace("/\"3\"+/", "e", $string);
$string = preg_replace("/\"3\"+/", "e", $string);

如何通过一次 preg_replace 呼叫完成所有符合条件的替换?

要仅替换引号内的那些 2 和 3,您可以执行 preg_replace_callback() 来完成。

$before = '754a49b393c2a0"33"b97"332"cb7"3"c3c07"2"';

$after = preg_replace_callback(
        '/"([^"]+)"/',
        function ($matches) {
            return str_replace( array( '2', '3' ), array( 'd', 'e' ), $matches[1] );;
        },
        $before
    );

echo $after;

使用此正则表达式在双引号之间查找 23 1 到 7 次

(?<=\")[23]{1,7}(?=\")

"233223322" won't be replaced with "deeddeedd" because it has more than 7 characters (9)

Demo

说明

[23]{1,7} 23 1 到 7 次

(?<=\") 前面加双引号

(?=\") 后接双引号

片段

$text = '"3"sca"""co"1"str"0"ctor""r"3"t"0"r"1""locat"5"o"133""0"27""754a49b393c2a0"33"b97"332"cb7"3"c3c07"2""co"1"str"0"ct"233223322"or""r"3"t"0"';

$regex = '/(?<=\")[23]{1,7}(?=\")/';

$text = preg_replace_callback($regex, 
    function ($m) {
        switch ($m[0]) {
            case '2': return 'd';
            case '3': return 'e';
            // Add other cases here ...
        }
    },
    $text
);

echo $text;

Online demo

首先,我建议的代码。然后回顾本页所采用的技术。

代码:(Demo)

echo preg_replace_callback('/"([23]{1,7})"/',
        function ($m) {
            return str_replace(['2', '3'], ['d', 'e'], $m[1]);
        },
        $text
    );

Stephane Janicaud 和 BA_Webimax 的 preg_replace_callback() 答案在执行中有好的部分和不太好的部分,但总体逻辑是合理的。我将花一些时间来隔离一些 weakness/opportunities 并提供一些改进。

关于模式:

Stephane 的模式:/(?<=\")[23]{1,7}(?=\")/ 误解了问题并在输入字符串中留下了双引号。他写了最合适的字符 class 和量词表达式(出现一到七次),但环视对模式效率造成了不必要的沉重负担;另外,双引号前的反斜杠是不必要的。此模式以惊人的 407 steps.

评估 OP 的输入字符串

接下来是对 BA_Webimax 模式的改编。他发布的模式不提供仅针对 23 的所需准确性,而是提供任何非双引号字符。对于此比较,我将使用 ~"([23]{1,7})"~。这是一个非常整洁和有效的模式——没有使用环视,唯一的拖累是捕获组。此模式以可观的 142 steps.

评估字符串

关于字符替换:

因为 Stephane 将一到七个字符传递给匿名函数并且 switch 案例仅检查 23 的精确匹配,他的回答结束了通过 消除第 3 和第 4 个匹配项 的字符串。这使得答案完全错误。 (Add other cases 注释对于开发人员编写代码来说并不合理 yatta yatta —— 他们为什么要编写代码?)

BA_Webimax 在第一个捕获组字符串上使用 str_replace() 执行智能、直接、高效的操作。

我使用输入字符串检查了 3v4l.org 的性能速度,str_replace() 在 php7.2 上的性能速度略高于 strtr()。也就是说,执行真正的基准测试将涉及大量输入数据——我只是没有走那条路。

单一功能替换:

  • str_replace(['2', '3'], ['d', 'e'], $m[1]);
  • strtr($m[1], ['2' => 'd', '3' => 'e']);