Do you know where your variables are? PerlMonks

### Search for abcNUMBERdef, make it a variable, then do math?

by Jesse Smith (Novice)
 on Jan 22, 2011 at 05:59 UTC Need Help??
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.
[download]```

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);
[download]```

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;
[download]```

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
[download]```
```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.
[download]```
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 )
[download]```
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");
[download]```
and Line 19 is use LWP::Simple;
Re: Search for abcNUMBERdef, make it a variable, then do math?
by Albannach (Prior) 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
[download]```
which gives
```Today:  1.63
Yesterday:  2.22
This Month: 45.44
Last Month: 21.40
[download]```
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.
[download]```

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

```...
foreach my(\$pair) (@pairs){
...
[download]```

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

```foreach my \$pair (@pairs){
[download]```

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

Log In?
 Username: Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://883659]
Approved by Corion
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (6)
As of 2017-06-24 04:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
How many monitors do you use while coding?

Results (556 votes). Check out past polls.