Search code examples
phparraysregexstringzero-padding

Pad all dot-delimited substrings to the same length for all strings in array


I have this array:

$versions = [
    '1',
    '1.0.2.4',
    '1.1.0',
    '1.12.547.8'
];

And I want:

$versions = [
    '001',
    '001.000.002.004',
    '001.001.000',
    '001.012.547.008'
];

But, if I have this:

$versions = [
    '1',
    '1.12'
];

I want this:

$versions = [
    '01',
    '01.12'
];

In other words, each string chunk must have same len of max chunk length considering every chunk throughout the array.

Explanation:

I have an array with variable elements number. Each element is a string containing a variable amount of groups of digits -- each separated by a dot. Each digit group has a variable length. I want to pad each sequence of digits so that all array sub-groups have the same length as the max group length.

In the first example, max length is 3 (longest number: 547), so all groups of final array have 3 digits (001, 000, ...). In the second example, max length is 2 (12), so all groups have 2 digits (01, 01, 12).

My solution:

$max = max(
    array_map(
        'strlen',
         call_user_func_array(
            'array_merge',
            array_map(
                function($row) {
                    return explode( '.', $row );
                },
                $versions
            )
        )
    )
);
foreach($versions as &$version)
{
    $version = preg_replace(
        '/\d*(\d{' . $max . '})/',
        '\1',
        preg_replace(
            '/(\d+)/',
            str_repeat('0', $max) . '\1',
            $version
        )
    );
}

Explained:

$tmp = array_map(
    function($row) {
        return explode('.', $row );
    },
    $versions
);
$tmp = call_user_func_array('array_merge', $tmp);
$tmp = array_map( 'strlen', $tmp );
$max = max($tmp);

$tmp = preg_replace('/(\d+)/', str_repeat('0', $max ) . '\1', $version );
$version = preg_replace( '/\d*(\d{' . $max . '})/', '\1', $tmp);

Someone have any ideas on how to simplify the process?


Solution

  • Well you can just simplify everything what you already did:

    First we can implode() the array into a string and match all numbers with preg_match_all().

    To then get the longest number we just use array_map() with strlen() as callback and get the longest number with max().

    Then when you know your pad length you can go through your array with preg_replace_callback() and pad your numbers with str_pad().

    Code:

    <?php
    
        $versions = [ '1', '1.0.2.4', '1.1.0', '1.12.547.8' ];
    
        preg_match_all("/\d+/", implode(".", $versions), $m);
        $max = max(array_map("strlen", $m[0]));
    
        $new = preg_replace_callback("/(\d+)/", function($m)use($max){
            return str_pad($m[1], $max, "0", STR_PAD_LEFT);
        }, $versions);
    
        print_r($new);
    
    ?>