【问题标题】:How to replace specific numbers (within a length limit) with specific letters?如何用特定字母替换特定数字(在长度限制内)?
【发布时间】:2017-10-20 00:59:33
【问题描述】:

我正在尝试使用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 调用完成所有符合条件的替换?

【问题讨论】:

  • 您为什么要尝试替换组合,例如322?你把事情复杂化了。
  • 我正在尝试第 3 方网络抓取,如果我替换,他们会在其中隐藏获取字符串,我将获得完整的获取价值
  • 替换前 754a49b393c2a0"33"b97"332"cb7"3"c3c07"2" 替换后 754a49b393c2a0eeb97eedcb7ec3c07d
  • 然后是 domain/get_id=754a49b393c2a0eeb97eedcb7ec3c07d
  • 这似乎是一个有缺陷的系统。您只能使用 10 个字符。

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


【解决方案1】:

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

代码:(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}(?=\")/ 误解了问题并在输入字符串中留下了双引号。他编写了最合适的字符类和量词表达式(出现 1 到 7 次),但是环视对模式效率造成了不必要的沉重负担;此外,双引号前的反斜杠是不必要的。此模式以高达 407 steps 的形式评估 OP 的输入字符串。

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

关于字符替换:

因为 Stephane 将一到七个字符传递给匿名函数,并且 switch 案例仅检查 23 的完全匹配,所以他的回答结束于通过 消除第三个字符来破坏字符串和第 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']);

【讨论】:

    【解决方案2】:

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

    (?<=\")[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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 只替换“数字”,不超过7个字符
      • @Christian 编辑以更好地匹配您正在做的事情。
      • 如何在这个替换函数中设置[2-9]{1,7}?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-07-23
      • 2019-01-23
      • 1970-01-01
      • 2017-02-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多