正则表达式子串的长度

I receive a string conformed by numbers and points. I need those numbers to have a minimum length of 3, so, I have to add one or more zeros in from of the numbers with a lower length.

Example:

If I have:

233.14.205.1.194056.270132

I need it to be:

233.014.205.001.194056.270132
    ↑       ↑↑

(Note the 014 where there was a 14 and the 001 where there was a 1)

I know I can explode the string, add the zeros I need and implode it again, but I want not to create a function for something that can solved with a native function (preg_replace) and I am not very good with regex (yet).

Using explode -> zero padding -> implode will indeed be straight forward.

Since you're specifically asking for preg_replace way of doing it here it is:

$s = '233.14.205.1.194056.270132'

$repl = preg_replace(array('/\b\d\b/', '/\b\d\d\b/'), array('00$0', '0$0'), $s);
//=> 233.014.205.001.194056.270132

Here we're passing a 2 element array of regex to preg_replace and inserting singe or double zeroes before the matched double/single digit.

You likely don't need a regular expression for this as you could simply split your string into an array via the explode() function and then pad each of your sections via array_map() and str_pad() respectively then finally use implode() to fit everything back together :

$input = '233.14.205.1.194056.270132';
$output = implode(".",array_map(function($s) { return str_pad($s,3,"0", STR_PAD_LEFT); },explode(".",$input)));

You can use this replacement:

$str = preg_replace('~\.(?!\d{3})|(?=\b\d\b)~', '${0}0', $str);

demo

The pattern uses two branches:

  • the first matches a dot not followed by 3 digits (in this case the replacement is the dot and an additional zero)
  • the second matches only the position before a single digit (in this case the replacement is only a zero since the whole match is empty).

When there are already two digits, only the first branch succeeds, but when there's only one digit the first branch succeeds and the second branch succeeds too at the next position in the string (immediately after the dot).

Note that you can use this pattern only for three digits, you can't extend it for more digits. A way that works for the number of digits you want can be:

$str = array_reduce(explode('.', $str), function ($c,$i) {
    return sprintf("%s%s%03d", $c, empty($c)?'':'.', $i);
});

or:

$str = preg_replace_callback('~\b\d{1,2}\b~', function ($m) {
    return sprintf("%03d", $m[0]);
}, $str);