2

I have a string from which I want to replace only the odd positions by a random digit.

For Example, the string is '123456'. Now the output I want is '528496'; Note that the digits 1,3,5 in odd positions are replaced by random digits 5,8,9.

I know how to do this using a PHP loop but was wondering if it could be done using a regex.

I found the following two relevant solutions on the web but still wasn't able to make it work.

Solution 1

echo preg_replace('/(.)./', '$1 ', $str);

Solution 2

echo preg_replace_callback('/\d/', function() {
    return chr(mt_rand(97, 122));
}, $str);

PS: I tried to comment on these questions but since I just have reputation of 5 I was not able to :(

BadHorsie
  • 14,135
  • 30
  • 117
  • 191
  • 1
    Try `preg_replace_callback('/.(.)/s', function($m){ return chr(mt_rand(48, 57)) . $m[1]; }, '123456');`, see https://3v4l.org/8dDmL – Wiktor Stribiżew Sep 07 '20 at 16:55
  • you specifically asked for regex, but alternatively could use str_split, array_map, modulo if odd replace, join back together https://3v4l.org/h8U0A – Lawrence Cherone Sep 07 '20 at 17:15
  • No need to use `chr()`, you can use `mt_rand(0, 9)`. Starting with PHP 7.4 you can even write: `echo preg_replace_callback('/.(.)/', fn($m) => rand(0,9) . $m[1], '123456');` – Casimir et Hippolyte Sep 07 '20 at 17:16
  • My plea for the three of you to stop posting answers as comments was scrubbed before any action was taken, so I don't know if you got the ping. Please decide whether or not you would like to transfer your comment to an answer. Regardless, please delete your resolving comments. – mickmackusa Oct 27 '20 at 15:24

2 Answers2

1

Replace characters at odd index

echo preg_replace_callback('/.(.|$)/', function ($matches) {
    return rand(0, 9) . $matches[1];
}, $str);

Replace characters at even index

echo preg_replace_callback('/(.)./', function ($matches) {
    return $matches[1] . rand(0, 9);
}, $str);

Notes

If your PHP version is less than 7.1, you shouldn't use rand() as it was a bad function which didn't work properly. Use mt_rand(0, 9) instead.

If you need the random numbers to be cryptographically secure, use random_int(0, 9) instead. This function is available in PHP 7.

BadHorsie
  • 14,135
  • 30
  • 117
  • 191
  • 1
    Thanks! It works perfect, However what needs to be changed if instead of the odd I want to replace the even position numbers? –  Sep 07 '20 at 18:09
1

You can perform the replacements without referencing the matched string at all. Only keep the single character which must be replaced.

Code: (PHP7.4 Demo)

replace odd positions:

echo preg_replace_callback(
         '/^.|.\K./',
         fn() => rand(0,9),
         '1234567'
     );

replace even positions:

echo preg_replace_callback(
         '/.\K./',
         fn() => rand(0,9),
         '1234567'
     );
mickmackusa
  • 43,625
  • 12
  • 83
  • 136