Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Regular expression

by nysus (Parson)
on Jun 07, 2001 at 20:17 UTC ( #86624=perlquestion: print w/replies, xml ) Need Help??

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

So I'm going through the Almighty Camel and reading the Gory Details on REs and I come across this little wonder:
# put commas in the right places in an integer 1 while s/(\d)(\d\d\d)(?!\d)/$1,$2/;
Which would take something like '3333333431234321234' and convert it nicely to 3,333,333,431,234,321,234. How does this work? I comprehend the RE itself and that the while forces looping when the condition is true but what does that '1' do?

$PM = "Perl Monk's";
$MCF = "Most Clueless Friar";
$nysus = $PM . $MCF;

Replies are listed 'Best First'.
(tye)Re: Regular expression
by tye (Sage) on Jun 07, 2001 at 20:50 UTC

    No one would take the bait in the chatterbox, so I'll post a node instead...

    You can use the following do-nothing values:

    • 0
    • 1
    • "ignore"
    • "diabolic"
    • "ds..."
    Any other values can get you warnings. I prefer 0 as it is much clearer that you intend it to do nothing. q-:

    Oh, and the valid do-nothing constant strings only have to start with the same two letters as one of the strings I listed above.

            - tye (but my friends call me "Tye")
      Yes yes, we all remember the node about "ig" and "ds" and "di" being legacy Perl 4 things...
      /* from op.c */ if (ckWARN(WARN_VOID)) { useless = "a constant"; /* the constants 0 and 1 are permitted as they are conventionally used as dummies in constructs like 1 while some_condition_with_side_effects; */ if (SvNIOK(sv) && (SvNV(sv) == 0.0 || SvNV(sv) == 1.0)) useless = 0; else if (SvPOK(sv)) { /* perl4's way of mixing documentation and code (before the invention of POD) was based on a trick to mix nroff and perl code. The trick was built upon these three nroff macros being used in void context. The pink camel has the details in the script wrapman near page 319. */ if (strnEQ(SvPVX(sv), "di", 2) || strnEQ(SvPVX(sv), "ds", 2) || strnEQ(SvPVX(sv), "ig", 2)) useless = 0; } }


      japhy -- Perl and Regex Hacker
      Don't forget, "0 but true"

        #!/usr/bin/perl -w $_= "193287461528"; "0 but true" while s/(\d)(\d\d\d)(\D|$)/$1,$2$3/; print;
        produces:
        Useless use of a constant in void context at warn.pl line 3. 193,287,461,528

        because the "0 but true" doesn't yet have a numeric value so the "is 0 or 1" test doesn't even get attempted.

        To get "0 but true" to work as an "unwarned useless constant", you have to jump through some interesting hoops:

        #!/usr/bin/perl -w $_= "193287461528"; sub zero() { "0 but true" } BEGIN { if( @ARGV ) { eval '0+zero'; } } zero while s/(\d)(\d\d\d)(\D|$)/$1,$2$3/; print;
        produces
        $ perl warn.pl Useless use of a constant in void context at warn.pl line 9. 193,287,461,528 $ perl warn.pl x 193,287,461,528
        The "()" in "sub zero()" is required for Perl to compile uses of "zero" as a constant (instead of as a subroutine call). The "0+zero" causes Perl to cache a numeric value for the "zero" constant. But you'll note that this caching is done at compile time so I have to use stringy eval to prevent it from happening when I don't want it to. But stringy eval also prevents it from happening at compile time even if that code gets run so I have to use a BEGIN block to get conditional compile-time behavior.

        So, how to use "0 but true" as a unwarned useless constant can be reduced to:

        #!/usr/bin/perl -w $_= "193287461528"; sub zero() { "0 but true" } zero while s/(\d)(\d\d\d)(\D|$)/$1,$2$3/; print; my $x= 0+zero;

                - tye (but my friends call me "Tye")
Re (tilly) 1: Regular expression
by tilly (Archbishop) on Jun 07, 2001 at 20:30 UTC
    Well your action is all in the RE, so you don't have to do anything in your loop. But you need something there else you wouldn't have a loop.

    1 just happens to be a convenient useless thing you can calculate in the body of the loop. Put anything useless there and it will work. But 1 is kind of traditional.

      So the '1' is taking the place of '{}'? It looks like you are right because I try
      while (s/(\d)(\d\d\d)(?!\d)/$1,$2/){}
      and that works.

      So this line is similar to the form 'do x while (this is true)' where the 'do x' in this case is just '1', which does nothing. I think I see, now. Thanks!

      $PM = "Perl Monk's";
      $MCF = "Most Clueless Friar";
      $nysus = $PM . $MCF;

        Exactly!
Re: Regular expression
by MeowChow (Vicar) on Jun 07, 2001 at 22:52 UTC
    I usually prefer to write these sorts of expressions as below, so as to make them less "silly":
    { s/(\d)(\d\d\d)(?!\d)/$1,$2/ && redo }
       MeowChow                                   
                   s aamecha.s a..a\u$&owag.print
       && redo

      I like that. Thanks for sharing it.

Re: Regular expression
by bwana147 (Pilgrim) on Jun 07, 2001 at 20:32 UTC

    Nothing! The "1" does nothing. Well, it returns a value of 1, that is immediately thrown away. Only the condition in the while is interesting here, and its side effects. You could have written:

    while (s/(\d)(\d\d\d)(?!\d)/$1,$2/) {}

    but it used to be slower in ancient version of Perl (I've read this in the Camel Book or the CookBook). Both Ways To Do It should be equivalent nowadays, but some habits die hard.

    --bwana147

Re: Regular expression
by lestrrat (Deacon) on Jun 07, 2001 at 20:32 UTC

    The 1 doesn't do anything. Really

    Seems weird, but in perl, just like the trailing "1;" in the end of a "require"'d file, a line consisting of a thingie ( whether it may be a scalar, array, hash, whatever ) is totally valid

    So the equivalent of above code is

    while( s/(\d)(\d\d\d)(?!d)/$1,$2/ ) { 1; ## do nothing, let the regex go until it no longer matche +s }
      Please don't confuse the 1 in this example (which indeed is just there for there has to be something there) with the 1; at the end of a perl module!! The 1; statement at the end of a module is truly needed as a returnvalue to the require statement. Substitute it to a 0 and watch the difference. In this example here you could substitue the 1 with a 0, which would change nothing at all...
      --
      use signature; signature(" So long\nAlfie");

        Hmm, sorry if it was misleading, but I think it's a "statement" nonetheless, no?

        package foo; sub foo { 1; } 1;

        Besides the fact that a required file needs a "true" value returned, I don't think the 1 at the end of the file is any different from the 1 in a sub or any block of code?

        Syntactically, yeah, they mean different things, but I believe the mechanism that goes behind there are the same...

        That was sort of where I was trying to get at, if it makes any sense

Re: Regular expression
by alfie (Pilgrim) on Jun 07, 2001 at 20:36 UTC
    The 1 at the start of the line does nothing - see it as a nop (no operation). Well, to be honest, it does something: It evaluates to 1, if you would use it. It could also be written as
    while (s(\d)(\d\d\d)(?!\d)/$1,$2/) {};
    If you count the characters this line is a little longer, but not really more readable.
    --
    use signature; signature(" So long\nAlfie");

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://86624]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (5)
As of 2022-05-16 07:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Do you prefer to work remotely?



    Results (62 votes). Check out past polls.

    Notices?