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

时间:2017-05-19 19:35:34

标签: php regex preg-replace preg-replace-callback

我正在尝试使用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

这些是正确替换的例子:

  • "3"变为e
  • "23"变为de
  • "33"变为ee
  • "32"变为de
  • "333223"变为eeedde

我的编码尝试:

$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调用进行所有符合条件的替换?

3 个答案:

答案 0 :(得分:1)

要仅替换引号内的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;

答案 1 :(得分:0)

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

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

  

“233223322”不会被“deeddeedd”替换,因为它有超过7个字符(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

答案 2 :(得分:0)

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

代码:(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()答案在执行过程中有很好的组件和不太好的组件,但一般的逻辑是合理的。我会花一点时间来隔离一些弱点/机会并提供一些改进。

关于模式:

Stephane的模式:/(?<=\")[23]{1,7}(?=\")/误解了问题,并在输入字符串中留下双引号。他编写了最合适的字符类和量词表达式(一到七次出现),但外观对模式效率造成了不必要的沉重负担;另外,双引号前的反斜杠是不必要的。这种模式在一个惊人的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']);