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

Hi Guys,
   I'm feeling a bit dense today. I've got a string of numbers like:-
20050725
I want to split it into 3 parts. So I have 2005 07 and 25 in separate variables. I can think of a few ways of doing it but they all seem long winded and I'm sure there is a bloody easy way of doing it.

Been working really late, my brain just isn't working right now.

Lyle

Replies are listed 'Best First'.
Re: Splitting up a string by lengths
by ikegami (Patriarch) on Jul 25, 2005 at 14:38 UTC

    The most efficient solution is:

    my ($y, $m, $d) = unpack('a4a2a2', $str);

    But the following solutions also work:

    my $y = substr($str, 0, 4); my $m = substr($str, 4, 2); my $d = substr($str, 6, 2);

    or

    my ($y, $m, $d) = $str =~ /(.{4})(.{2})(.{2})/;

    (Update:)

    or the sillier

    $str =~ /(.{4})/g; my $y = $1; $str =~ /(.{2})/g; my $m = $1; $str =~ /(.{2})/g; my $d = $1;

    To convert the returned strings into numbers (which removes the leading 0s), prepend map { 0+$_ }. For example,

    my ($y, $m, $d) = map { 0+$_ } unpack('a4a2a2', $str);

    You can always pad with 0s later:

    printf("%04d/%02d/%02d\n", $y, $m, $d);

    or

    $formatted = sprintf("%04d/%02d/%02d", $y, $m, $d);
      I'd avoid the sillier approach, it may fail miserably for badly formatted input strings:
      #!/usr/bin/perl use strict; use warnings; my $str = '2004'; $str =~ /(.{4})/g; my $y = $1; $str =~ /(.{2})/g; my $m = $1; $str =~ /(.{2})/g; my $d = $1; print "$y-$m-$d\n"; __END__ 2004-2004-20

      Flavio
      perl -ple'$_=reverse' <<<ti.xittelop@oivalf

      Don't fool yourself.
Re: Splitting up a string by lengths
by davorg (Chancellor) on Jul 25, 2005 at 14:41 UTC

    You want unpack.

    my $date = '20050725'; my ($y, $m, $d) = unpack('a4a2a2', $date); print "$y / $m / $d\n";
    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

      ^^^ Nice!! I never would've thought of that. I'll be using that a lot in the future.

      Update: This is turning into a nice TIMTOWTDI thread!
        in reasonably recent perls, you can do stuff like this:
        my @cc = unpack("(A4)4", "1234567890123456");
        instead of the more verbose
        my @cc = unpack("A4A4A4A4", "1234567890123456");
        I've used it in the past with great success. Besides...it might improve your golf game. :)

        thor

        Feel the white light, the light within
        Be your own disciple, fan the sparks of will
        For all of us waiting, your kingdom will come

Re: Splitting up a string by lengths
by wazoox (Prior) on Jul 25, 2005 at 14:51 UTC
    OK, here are a few options I think of ATM:
    #!/usr/bin/perl use strict; use warnings; my $s="20050725"; ############## # with substr my ($year, $month, $day) = ( substr($s, 0, 4), substr($s, 4, 2), subst +r($s, 6, 2)); print "gives : $year, $month, $day \n"; ############## # with a regexp ($year, $month, $day) = $s =~ /(\d{4})(\d\d)(\d\d)/ ; print "gives : $year, $month, $day \n" ; ############## # with split and join my @el=split '', $s; ($year, $month, $day) = ( join('', @el[0,1,2,3]), join('', @el[4,5]) +, join('', @el[6,7]) ) ; print "gives : $year, $month, $day \n" ; ############## # with shift @el=split '', $s; # zero the vars $year=$month=$day=undef; $year .= shift @el for 0..3; $month .= shift @el for 0..1; $day .= shift @el for 0..1; print "gives : $year, $month, $day \n" ;
    Cheers :)
Re: Splitting up a string by lengths
by AReed (Pilgrim) on Jul 25, 2005 at 14:45 UTC
    I'm all in favor of being reasonably long-winded if it makes it clear what's going on to future maintenance programmers (or me two months later).
    my $datestring = "20050725"; my $year = substr($datestring,0,4); my $month = substr($datestring,4,2); my $day = substr($datestring,6,2); print "$month/$day/$year\n";

      While other forms can be far worse, AND eror-prone, I'm not sure this qualifies as a shining example of readable and maintainable.

      I haven't used unpack very much outside dismantling dates, but I found it worth the inconvenience of learning the basic use of the function, because it is so so simple and clear, other than the horrific confusion of what all the codes signify, and which one means what. Luckily, named variables can conceal the format string.

      my ( $year, $month, $day ) = unpack $YYYYMMDD_format, $date_string;
      TomDLux

      --
      TTTATCGGTCGTTATATAGATGTTTGCA

Re: Splitting up a string by lengths
by monkfan (Curate) on Jul 25, 2005 at 14:41 UTC
    perl -e ' $num = 20050725; $num=~ s/(\d{4})(\d{2})(\d{2})/$1 $2 $3/; print "$1 $2 $3\n";'
    prints:
    2005 07 25
    Regards,
    Edward
Re: Splitting up a string by lengths
by inman (Curate) on Jul 25, 2005 at 16:10 UTC
    # Straight assignment my ($year, $month, $day) = $data =~ /(\d{4})(\d{2})(\d{2})/; # With optional default values my ($year, $month, $day) = $data =~ /(\d{4})(\d{2})(\d{2})/ ? ($1,$2,$ +3) : (1970,1,1);
Re: Splitting up a string by lengths
by Transient (Hermit) on Jul 25, 2005 at 14:38 UTC
    What ways have you tried? One is to use substr a few times.
Re: Splitting up a string by lengths
by Anonymous Monk on Jul 25, 2005 at 22:55 UTC
    Once you've split up your string by lengths, you'll be rich!

    I can hear the adverts now:

    Destroy 99% of known household pests with pre-sliced, rustproof, easy-to-handle, low-calorie cosmicperl's individual emperor stringettes; free from artificial coloring; as used in hospitals!

    Wait, I see a television commercial... There's this nude woman in a bath holding a bit of your string. That's great, great, but we need ...