http://qs321.pair.com?node_id=1194845

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

Hi Monks, I'm hoping someone can assist with a one-liner. I'm trying to pad a leading zero to a 5 digit time. I'm close, but I'm missing something.

perl -i.bak -pe 's/\<time\>(\d+)\<\/time\>/\<time\>sprintf("%06d",$1)\ +<\/time\>/ if /\<time\>(\d{5})\<\/time\>/' <file>

I'm ending up with the following:

<time>sprintf("%06d",10001)</time>

and I'm expecting this:

<time>010001</time>

any help would be greatly appreciated!

Replies are listed 'Best First'.
Re: Using SprintF in S & R
by herveus (Prior) on Jul 11, 2017 at 18:06 UTC
    Howdy!

    The right hand side of s/// does not execute code unless you use the "e" modifier.

    So, s/\<time\>(\d+)\<\/time\>/\<time\>sprintf("%06d",$1)\<\/time\>/e is what you want. Note the "e" after the last slash.

    Edit to correct placement of "e" modifier. Thanks Laurent. Too many slashes and backslashes!

    yours,
    Michael
      The right hand side of s/// does not execute code unless you use the "e" modifier.

      Would you bet your money on that statement? I would not.

      You are right, s/// usually does not execute code without the /e modifier. But Perl would not be Perl if you could not mess around with that. Note that even if you could mess with perl, you probably should not.

      I'll abuse a trick invented by Andrew Pimlott, that I saw first in the "Perl hardware store" talks (1, 2, 3, 4) by Dominus:

      #!/usr/bin/perl use strict; use warnings; sub TIEHASH { return bless {},$_[0]; } sub FETCH { return $_[1]; } tie my %X,__PACKAGE__; my $foo='look! no eval: 3735928559'; $foo=~s/(\d+)/$X{sprintf '0x%08X',$1}/; print $foo;
      >perl eval.pl look! no eval: 0xDEADBEEF >

      But there is also a way without tie magic. Dereferencing an anonymous array reference:

      #!/usr/bin/perl use strict; use warnings; my $foo='look! no eval: 3735928559'; $foo=~s/(\d+)/${[sprintf '0x%08X',$1]}[0]/; print $foo;
      >perl eval2.pl look! no eval: 0xDEADBEEF >

      Both tricks (ab)use the fact that s/// interpolates the replacement expression, unless you force it not to do so (using ' as the delimiter instead of /).

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
      I guess you mean to have the "e" modifier at the end of the substitution, not after the regex of the statement modifier (the if conditional).

      Besides, I don't think you need to escape the < and > characters.

        Howdy!

        Ack! Thanks for pointing that out. The perils of too much copy and paste.

        yours,
        Michael
Re: Using SprintF in S & R
by Anonymous Monk on Jul 11, 2017 at 17:48 UTC
    s{<time>(\d+)</time>}{sprintf "<time>%06d</time>", $1}eg

      thank you! ...worked like a charm.