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

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

How do you make perl search for say today([^&]+)today, where ([^&]+) is any number, then make it a variable, for example $12345. Then change it to 123.45, and then do math to it, 123.45*.40 = 49.38 with 49.38 being what the $12345 variable is at the end??? What perl is searching is... Today: today408today Clicks: 34 Yesterday: yesterday555yesterday Clicks: 61 This Month: this11360this Clicks: 812 Last Month: last5350last Clicks: 454 where the numbers change. The closest I can get is... $id3 =~ /today(\d+)today/; my $ans = $1 * .40; $final = ($ans / 100); $id4 =~ /yesterday(\d+)yesterday/; my $ans2 = $2 * .40; $final2 = ($ans2 / 100); $id5 =~ /this(\d+)this/; my $ans3 = $3 * .40; $final3 = ($ans3 / 100); $id6 =~ /last(\d+)last/; my $ans4 = $4 * .40; $final4 = ($ans4 / 100); { print "Content-Type: text/html\n\n"; print <<EOM; $id2 <HR> Original Number: $1 - $2 - $3 - $4 <HR> After it's been converted: $ans - $ans2 - $ans3 - $ans4 After being divide by 100: $final - $final2 - $final3 - $final4 which spits out Original Number: 5350 - - - After it's been converted: 2140 - 0 - 0 - 0 After being divide by 100: 21.4 - 0 - 0 - 0 It only messes with the last5350last, even if I only have the code that should mess with today408today.

Replies are listed 'Best First'.
Re: Search for abcNUMBERdef, make it a variable, then do math?
by CountZero (Bishop) on Jan 22, 2011 at 07:45 UTC
    Every regex starts an new sequence of $1, $2, $3, ... again. Therefore each of your captures goes into the same $1. You do capture all the numbers, but overwrite them with the capture of the next regex and therefore it ends up with the last capture in $1 and all other still zero (in numeric context).

    As a best practice, you should waste no time or processor cycles before you put the results of the captures stored in $1 and its brethren into regular variables. Never ever trust them to "keep" their values. A subroutine far far away in another module my decide at any moment to trash them for its own use.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

      $id4 =~ /yesterday(\d+)yesterday/; my $ans2 = $2 * .40; $final2 = ($ans2 / 100);

      Jesse Smith: Further to CountZero's reply: in the above quoted and in subsequent steps in the OPed code, the capture variable  $2 (and subsequently  $3 $4) is used in a calculation, but there is no second (or third or fourth) capture group to populate this variable with a defined value. The fact it is undefined would have been made evident to you had you been using warnings (and strictures for good measure – and diagnostics for even better measure since you are learning Perl):

      use warnings; use strict; use diagnostics;

      See perlre, perlrequick, perlretut, perlreref for regular expression (re) on-line documentation, or  perldoc perlre etc for local installation documentation.

Re: Search for abcNUMBERdef, make it a variable, then do math?
by PeterPeiGuo (Hermit) on Jan 22, 2011 at 06:15 UTC

    Use a hash or array to index information, don't make the index part of your variable name.

    Peter (Guo) Pei

Re: Search for abcNUMBERdef, make it a variable, then do math?
by cdarke (Prior) on Jan 22, 2011 at 06:18 UTC
    make it a variable, for example $12345

    Not sure why you would want to, but you cannot create a variable starting with a numeric explicitly, you would have to have 12,345 capturing parentheses groups.

    I'm not certain what it is you want, but would this do?
    #!/usr/bin/perl use warnings; use strict; my %nums; @nums{qw(today yesterday this last)} = undef; my $alts = join('|',keys %nums); while (<DATA>) { /($alts)(\d+)\1/; $nums{$1} = $2; } for my $key (keys %nums) { my $ans = ($nums{$key} * 0.4)/100; print "$key: $ans (from $nums{$key})\n" } __DATA__ Today: today408today Clicks: 34 Yesterday: yesterday555yesterday Clicks: 61 This Month: this11360this Clicks: 812 Last Month: last5350last Clicks: 454
      I'll try that out and post back. I'm just trying to change Today: today408today Yesterday: yesterday555yesterday This Month: this11360this Last Month: last5350last in to Today: 1.63 Yesterday: 22.22 This Month: 45.44 Last Month: 21.40 40% of what the number is, with the period added. By doing this math for each of them. For example... Today: today408today would do 408*.4/100=1.63200 with the '200' part taken off.
        SSH spits out
        root@wor [/home/site82/public_html/cgi-bin]# perl stats.cgi Prototype mismatch: sub main::head: none vs ($) at stats.cgi line 19 today: 0 (from ) last: 0 (from ) this: 0 (from ) yesterday: 0 (from )
        The first part of the script is
        if (length ($ENV{'QUERY_STRING'}) > 0){ $buffer = $ENV{'QUERY_STRING'}; @pairs = split(/&/, $buffer); foreach $pair (@pairs){ ($name, $value) = split(/=/, $pair); $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg +; $in{$name} = $value; } } my $id = param('id'); use LWP::Simple; $id2 = get ("http://www.domain.com/stats.php?id=$id");
        and Line 19 is use LWP::Simple;
Re: Search for abcNUMBERdef, make it a variable, then do math?
by Albannach (Monsignor) on Jan 22, 2011 at 15:04 UTC
    Unless you need to store the values for later use, I'd do it this way:
    use strict; use warnings; while(<DATA>) { if(/([\w\s]+:)\s([a-z]+)(\d+)\2/) { print "$1 ", sprintf("%5.2f\n",$3*0.4/100); } } __DATA__ Today: today408today Clicks: 34 Yesterday: yesterday555yesterday Clicks: 61 This Month: this11360this Clicks: 812 Last Month: last5350last Clicks: 454
    which gives
    Today: 1.63 Yesterday: 2.22 This Month: 45.44 Last Month: 21.40
    Edited: Removed unnecessary extra colon in print (I had captured it already from the input) and inserted actual output generated - duh!

    --
    I'd like to be able to assign to an luser

      #!/usr/bin/perl use warnings; use strict; if (length ($ENV{'QUERY_STRING'}) > 0){ my($buffer) = $ENV{'QUERY_STRING'}; my(@pairs) = split(/&/, $buffer); foreach my($pair) (@pairs){ ($name, $value) = split(/=/, $pair); my($value) =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1) +)/eg; $in{$name} = $value; } } my($id) = param('id'); use LWP::Simple; $id2 = get ("http://www.domain.info/stats.php?id=$id"); $id2 =~ s*\[Yesterday\] *Yesterday: *g; while(<DATA>) { if(/([\w\s]+:)\s([a-z]+)(\d+)\2/) { print "$1 ", sprintf("%5.2f\n",$3*0.4/100); } } spits out Missing $ on loop variable at stats.cgi line 9. on SSH.

        I would assume that Perl is right when it points you to line 9.

        ... foreach my($pair) (@pairs){ ...

        This is not valid Perl code. The valid Perl code would be (note the lack of parentheses)

        foreach my $pair (@pairs){

        But in all seriousness, why are you trying to do what is CGI.pm's job? Just use CGI; and then query $q->Vars to get a hash of parameters passed to your script. Don't parse query strings yourself.

        Its because you keep including that ENV{'QUERY_STRING'} garbage, get rid of it