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

In my quest for knowledge, I am experimenting and getting confused. Here I am trying to insert dashes between sets of 4 with no luck. I have tried hashes (#) instead of (d) with the same results. The format string is always returned: $CCformatted = sprintf 'dddd-dddd-dddd-dddd, $cardNum; I know the answer is simple, but so am I ;-)

Replies are listed 'Best First'.
Re: Formatting with sprintf
by kennethk (Abbot) on Nov 10, 2015 at 01:07 UTC
    The answers thus far do not really go into a why, so I will weigh in.

    sprintf is intended to take individual values and insert them into a template. In this case, your values do not remain continuous, so that means before you use a sprintf you need to separate the 4 digits sequences before re-joining them. You can split a couple of different ways:

    and you can join them together a couple different ways

    • join: my $CCformatted = join '-', @digits;
    • sprintf: my $CCformatted = sprintf '%04d-%04d-%04d-%04d', @digits;

    You can also do it with a compound operation like (my $CCformatted = $cardNum) =~ s/.{4}\K(?=.)/-/g;. TIMTOWTDI. I think my $CCformatted = join '-', unpack '(A4)*', $cardNum; is cleanest, but YMMV.


    #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

      I think I also prefer the join/unpack approach, but here's a regex with the highly prized "one-liner" property that works at least back to 5.8.9:

      c:\@Work\Perl>perl -wMstrict -le "print qq{perl version $]}; ;; for my $cc (qw( 1234987656785432 0000000000000000 0001000200030004 1000200030004000 )) { print qq{'$cc'}; ;; (my $fcc = $cc) =~ s{ \B (?= (?: ....)+ \z) }{-}xmsg; print qq{'$fcc' \n}; } " perl version 5.008009 '1234987656785432' '1234-9876-5678-5432' '0000000000000000' '0000-0000-0000-0000' '0001000200030004' '0001-0002-0003-0004' '1000200030004000' '1000-2000-3000-4000'


      Give a man a fish:  <%-{-{-{-<

Re: Formatting with sprintf
by LanX (Saint) on Nov 10, 2015 at 01:05 UTC
    you want this
    DB<150> sprintf "%d-%d-%d-%d", ('1234567890123456' =~ /(....)/g) => "1234-5678-9012-3456"

    or this

    DB<151> sprintf "%d%d%d%d-%d%d%d%d-%d%d%d%d-%d%d%d%d", split //, '12 +34567890123456' => "1234-5678-9012-3456"

    But I'd rather prefer this

    DB<153> join "-", ('1234567890123456' =~ /(....)/g) => "1234-5678-9012-3456"

    TIMTOWTDI ... depends if you always make sure that the input is 16 characters long.

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

    update

    kennethk++ msged me that leading 0 are a problem in the first approach

    DB<160> sprintf "%d-%d-%d-%d", ('0123456789012345' =~ /(....)/g) => "123-4567-8901-2345"

    this would fix it

    DB<161> sprintf "%04d-%04d-%04d-%04d", ('0123456789012345' =~ /(.... +)/g) => "0123-4567-8901-2345"

    but honestly, I doubt I would stick with this approach.

Re: Formatting with sprintf
by Anonymous Monk on Nov 10, 2015 at 00:44 UTC

    sprintf doesn't apply

    #!/usr/bin/perl # http://perlmonks.org/?parent=1147312;node_id=3333 use strict; use warnings; $| = 1; my $card = '1234543267679898'; my $CCformatted = $card =~ s/....\K\B/-/gr; print $CCformatted, "\n";

    I had to respond because I love Citabria's.

      I got a syntax error on the my @CC... line and not smart enough to find where; Would you like a ride in my Citabria?
        What version of perl are you running? \K was introduced to regular expressions in v5.10.0.

        #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

        Old perl ?

        my $CCformatted = join '-', $card =~ /..../g;

        Most of my PP hours were in Citabria's, but that was 41? years ago :)

Re: Formatting with sprintf
by Anonymous Monk on Nov 10, 2015 at 00:42 UTC

    what output are you trying to get?

    Please explain like this, type the actual characters my $input = ...; my $output = '....-....'; </c>

      This is a CGI script. I am validating a credit card number ($cardNum) and trying to format it to look like this: 1234-5678-9012-3456. I have confirmed that $cardNum contains a correct, 16-digit value. All attempts have resulted in either null or all zero format (0000-0000-0000-0000). Wish I were smarter....
        I know this is somewhat off-topic. You should consider using the module Regexp::Common::CC for credit card validation. Unfortunately, the SYNOPSIS is incomplete. You have to check the source code for the complete list of supported credit cards.
        Bill
        Someone asked about the version: This is perl, v5.8.8 built for x86_64-linux-thread-multi