http://www.perlmonks.org?node_id=1011209

walkingthecow has asked for the wisdom of the Perl Monks concerning the following question:

I have a scalar variable, and below are some examples of the values that may be in the variable:

1,2,3,4
8,9,10,11
7,8,9,10
12,13,14,15

Basically, what I'd like to do is to put a zero before any single digit (i.e., 9 becomes 09, 8 becomes 08, 10 stays 10, and so on). So, I know I can do this by splitting the scalar into an array, then go through each value of the array and say if ($value =~ /(\d)/) then make it 0$1, and then put it all back together. However, I am wondering if there is any way I can do it without splitting the scalar. For example, 8,9,10,11 becomes 08,09,10,11. I have the following code, but it only works in situations where they are all single digits (e.g., 1,2,3,4):
if ( $channels =~ /(\d,)(\d,)(\d,)(\d)/ ) { $channels = "0${1}0${2}0${3}0$4"; }

Replies are listed 'Best First'.
Re: Replacing matches within string without splitting.
by Athanasius (Archbishop) on Jan 02, 2013 at 06:44 UTC

    Another approach:

    #! perl use Modern::Perl; while (<DATA>) { chomp; s{\b(\d)\b}{0$1}g; say; } __DATA__ 1,2,3,4 8,9,10,11 7,8,9,10 12,13,14,15

    Output:

    16:42 >perl 462_SoPW.pl 01,02,03,04 08,09,10,11 07,08,09,10 12,13,14,15 16:42 >

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      That worked beautifully (in Perl 5.8 without Modern::Perl)! Thank you :)
      $channels =~ s{\b(\d)\b}{0$1}g;
Re: Replacing matches within string without splitting.
by BrowserUk (Patriarch) on Jan 02, 2013 at 06:44 UTC

    Use lookahead:

    $t = "1,2,3,4\n8,9,10,11\n7,8,9,10,\n12,13,14,15\n";; print $t;; 1,2,3,4 8,9,10,11 7,8,9,10, 12,13,14,15 $t =~ s[(\D|^)(?=\d(?:\D|$))][${1}0]g;; print $t;; 01,02,03,04 08,09,10,11 07,08,09,10, 12,13,14,15

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Replacing matches within string without splitting.
by NetWallah (Canon) on Jan 02, 2013 at 06:44 UTC
    Typically, leading zero printing, and other formatting is done using sprintf and friends:
    perl -E '$x="2,42,1,3"; printf "%.2d ",$_ for eval("($x)") ; print +"\n"' 02 42 01 03
    Update: Replaced with better example.

                 "By three methods we may learn wisdom: First, by reflection, which is noblest; Second, by imitation, which is easiest; and third by experience, which is the bitterest."           -Confucius

Re: Replacing matches within string without splitting.
by 2teez (Vicar) on Jan 02, 2013 at 06:39 UTC

    something like this?

    my @array = ( 1, 2, 3, 4, 8, 9, 10, 11, 7, 8, 9, 10, 12, 13, 14, 15 ); for (@array) { $_ < 10 ? print "0", $_, $/ : print $_, $/; }

    output

    01 02 03 04 08 09 10 11 07 08 09 10 12 13 14 15

    If you tell me, I'll forget.
    If you show me, I'll remember.
    if you involve me, I'll understand.
    --- Author unknown to me
Re: Replacing matches within string without splitting.
by johngg (Canon) on Jan 02, 2013 at 09:56 UTC

    A variation on the sprintf solutions using split, map and join.

    $ perl -E ' > say join q{,}, map { sprintf q{%02d}, $_ } split m{,} for qw{ > 1,2,3,4 > 8,9,10,11 > 7,8,9,10 > 12,13,14,15 > };' 01,02,03,04 08,09,10,11 07,08,09,10 12,13,14,15

    I hope this is of interest.

    Cheers,

    JohnGG

Re: Replacing matches within string without splitting.
by Anonymous Monk on Jan 02, 2013 at 08:29 UTC

    The /e switch coupled with sprintf?

    while (<DATA>) { s/(\d+)/ sprintf("%02d", $1) /ge; print $_; } __DATA__ 1,2,3,4 8,9,10,11 7,8,9,10 12,13,14,15
Re: Replacing matches within string without splitting.
by AnomalousMonk (Archbishop) on Jan 02, 2013 at 18:37 UTC

    Using only look-arounds and no captures. Express the conditions: insert '0' at every point that is:

    • not after a digit; and
    • before a solitary digit.

    perl -wMstrict -le "my @strs = ( '1,2,3,4', '8,9,10,11', '7,8,9,10', '12,13,14,15', '1,23,456', '123,45,6', ); ;; my $not_after_digit = qr{ (?<! \d) }xms; my $before_solitary_digit = qr{ (?= \d (?! \d)) }xms; ;; for my $s (@strs) { printf qq{'$s' -> }, $s; $s =~ s{ $not_after_digit $before_solitary_digit }{0}xmsg; print qq{'$s'}; } " '1,2,3,4' -> '01,02,03,04' '8,9,10,11' -> '08,09,10,11' '7,8,9,10' -> '07,08,09,10' '12,13,14,15' -> '12,13,14,15' '1,23,456' -> '01,23,456' '123,45,6' -> '123,45,06'