简体   繁体   中英

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

I am trying to use preg_replace to change numbers to letters, but only numbers wrapped in "" and not more than 7 characters in the substring.

Sample input string:

"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"

The desired effect is for every qualifying 2 to become d and every qualifying 3 to become e .

These are examples of correct replacements:

  • "3" becomes e
  • "23" becomes de
  • "33" becomes ee
  • "32" becomes de
  • "333223" becomes eeedde

My coding attempt:

$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);

How can I make all qualifying replacements with one preg_replace call?

To only replace those 2s and 3s inside quotes, you can do a preg_replace_callback() to accomplish that.

$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;

Use this regex to find either 2 or 3 between double-quotes from 1 to 7 times

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

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

Demo

Explanation

[23]{1,7} Either 2 or 3 from 1 to 7 times

(?<=\\") Precedeed by a double-quote

(?=\\") Followed by a double-quote

Snippet

$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

First, my suggested code. Then a review of the techniques employed on this page.

Code: ( Demo )

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

Stephane Janicaud's and BA_Webimax's preg_replace_callback() answers have good components and not-so-good components in the execution, but the general logic is sound. I'll take a moment to isolate some weakness/opportunities and offer some refinements.

Regarding the pattern:

Stephane's pattern: /(?<=\\")[23]{1,7}(?=\\")/ misunderstands the question and leaves the double quotes in the input string. He writes the most appropriate character class and quantifier expression (one to seven occurrences), but the lookarounds are an unnecessarily heavy burden on pattern efficiency; also, the backslash before the double quotes is needless. This pattern evaluates the OP's input string in a whopping 407 steps .

Next in line is an adaptation of BA_Webimax's pattern. His posted pattern does not offer the desired accuracy of only targeting 2 and 3 , but rather any non-double quote character. For this comparison, I'll use ~"([23]{1,7})"~ . This is a very tidy and effective pattern -- there are no lookarounds used, and the only drag is the capture group. This pattern evaluates the string in a respectable 142 steps .

Regarding the character replacement:

Because Stephane is passing one to seven characters to the anonymous function AND the switch cases are ONLY checking for exact matches of 2 or 3 , his answer ends of mangling the string by eradicating the 3rd and 4th matches . This makes the answer simply wrong. (The Add other cases comment is not a reasonable yatta yatta for developers to code up -- and why should they?)

BA_Webimax performs a smart, direct, efficient action using str_replace() on the first capture group string.

I checked the performance speeds on 3v4l.org and str_replace() edged out strtr() on php7.2 using the input string. That said, executing a real benchmark would involve a larger volume of input data -- I just didn't go down that path.

Single-Function Replacements:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM