How do I increment a value with leading zeroes in Perl? - perl

It's the same question as this one, but using Perl!
I would like to iterate over a value with just one leading zero.
The equivalent in shell would be:
for i in $(seq -w 01 99) ; do echo $i ; done

Since the leading zero is significant, presumably you want to use these as strings, not numbers. In that case, there is a different solution that does not involve sprintf:
for my $i ("00" .. "99") {
print "$i\n";
}

Try something like this:
foreach (1 .. 99) {
$s = sprintf("%02d",$_);
print "$s\n";
}
The .. is called the Range Operator and can do different things depending on its context. We're using it here in a list context so it counts up by ones from the left value to the right value. So here's a simpler example of it being used; this code:
#list = 1 .. 10;
print "#list";
has this output:
1 2 3 4 5 6 7 8 9 10
The sprintf function allows us to format output. The format string %02d is broken down as follows:
% - start of the format string
0 - use leading zeroes
2 - at least two characters wide
d - format value as a signed integer.
So %02d is what turns 2 into 02.

printf("%02d\n",$_) foreach (1..20)

print foreach ("001" .. "099")

foreach $i (1..99) {printf "%02d\n", $i;}

I would consider to use sprinft to format $i according to your requirements. E.g. printf '<%06s>', 12; prints <000012>.
Check Perl doc about sprinft in case you are unsure.

Well, if we're golfing, why not:
say for "01".."99"`
(assuming you're using 5.10 and have done a use 5.010 at the top of your program, of course.)
And if you do it straight from the shell, it'd be:
perl -E "say for '01'..'99'"

Related

Perl sequence of numbers with leading zeros

Is there some easy way (without sprintf and, of course, printf) to get a list of (001, 002, ... 100) in Perl?
In bash it was something like seq -w 1 100. What about Perl?
you mean like this?
for ('001'..'100') {
print "$_\n";
}
.. in a range, returns a list of values counting by ones, from the left value to the right value.
For more details about how to use range, please refer to:
Perldoc range operator and this link
Printf was created for problems like this. Using it will help you get the answers you want faster.
foreach my $number ( 1 .. 100 ) {
printf "%03d\n", $number;
}
The % is the "begin a format sequence"
The 0 is "leading zeros"
The 3 is "three digits minimum"
The d is "treat the parameter as digits (integer)"

using printf to create columnar data

I am new to perl and scripting in general. I have five variables that hold data and I need to print them as five columns next to each other. Here is the code I have now.
$i = 0;
foreach $line (<inf>){
chomp $line;
#line=split / +/, $line;
$i = $i + 1;
if ($i > $n+1) {
$i = 1;
$numdata = $numdata + 1;
}
if ($i == 1) {
printf "%20s\n", $n, "\n";
} else {
print $i-1, "BEAD", $line[$col], $line[$col+1], $line[$col+2], "\n";
}
# other statistics
}
The output I get from this looks like:
5
1BEAD0.00000e+000.00000e+000.00000e+00
2BEAD0.00000e+000.00000e+000.00000e+00
3BEAD0.00000e+000.00000e+000.00000e+00
4BEAD0.00000e+000.00000e+000.00000e+00
5BEAD0.00000e+000.00000e+000.00000e+00
5
1BEAD9.40631e-02-3.53254e-022.09369e-01
2BEAD-6.69662e-03-3.13492e-012.62915e-01
3BEAD2.98822e-024.60254e-023.61680e-01
4BEAD-1.45631e-013.45979e-021.50167e-01
5BEAD-5.57204e-02-1.51673e-012.95947e-01
5
1BEAD8.14225e-028.10216e-022.76423e-01
2BEAD2.36992e-02-2.74023e-014.47334e-01
3BEAD1.23492e-011.12571e-012.59486e-01
4BEAD-2.05375e-011.25304e-011.85252e-01
5BEAD5.54441e-02-1.30280e-015.82256e-01
I have tried using "%6d %9d %15.6f %28.6f %39.6f\n" before the variables in my print statement to try to space the data out; however, this did not give me the columns I hoped for. Any help/ suggestions are appreciated.
If you're using Perl and doing more complex stuff, you may want to look into perlform, which is designed for this kind of thing, or a module like Text::Table.
As for using printf though, you can use the padding specifiers to get consistent spacing. For instance, using the Perl docs on it, make sure the field width is before the .: your printf string should probably look something more like this (check out the "precision, or maximum width" section):
printf "%6.d %9.d %15.6f %28.6f %39.6f"
Also, if your things are in an array, you can just pass the array the second argument to printf and save yourself typing everything out. I've also prepended the two other items from your example with unshift:
unshift(#line, $i-1, "BEAD");
printf "%6.d %10s %15.6f %28.6f %39.6f\n", $line;
Note that the %s placeholders don't have the . precision specifier, so leave it out for that. If you want the e-notation for the numbers, use %e or %g instead of %f (%39.6e).
Also, for Perl questions, always check out Perl Monks - much of this answer was culled from a question there.
P.S. Given one of your example columns, here's the proof-of-concept script I tried to make sure everything worked:
perl -e '#line = (8.14225e-02,8.10216e-02,2.76423e-01);
unshift(#line, 4, "BEAD");
printf "%6.d %10s %15.6f %28.6f %39.6e\n", #line;'

Perfect matching is not working

I have a problem about perfect matching.I want to get the sum of positive and negative integers from a file .Also I want to get dates have same values in the file.
My File:
Hello -12, 3.4 and 32. Where did you
go on 01/01/2013 ? On 01/01/2013, we
went home. -4 plus 5 makes 1.
03/02/2013
Results I should be getting:
-16 //the sum of negative integers.
38 //the sum of positive integers.
2 //total number of unique dates :)
My code is:
$sum=0;
$summ=0;
while (<>) {
foreach ($_=~ /-\d+/g)
{
$sum+=$_;
}
foreach ($poz=~ /^\d+?$/g) {
$summ+=$poz;
}
foreach (/\d{2}\/\d{2}\/\d{4}/) {
$count++;
}
}
print "$sum\n";
print "$summ\n";
print "$count\n";
The output I am getting is:
-16
0
2
I can not get the value of the sum of positive numbers. Could you please help me?
First of all, always use use strict; use warnings;. It would have found your first error: The use of $poz without ever giving it a value. Twice!
A positive integer is a sequence
Not preceded by -.
Not preceded by a digit.
Not preceded by ..
Not preceded by /.
Consists of digits
Not followed by . plus digits. (Well, you might consider 4.0 an integer, but I doubt it.)
Not followed by a digit.
Not followed by /.
(?<![\-\d./])\d+(?![\d/])(?!\.\d)
A negative integer is a sequence
Consists of - followed by digits
Not followed by . plus digits. (Well, you might consider 4.0 an integer, but I doubt it.)
Not followed by a digit.
-\d+(?!\d)(?!\.\d)
So,
use strict;
use warnings;
my $sum_p = 0;
my $sum_n = 0;
my $dates = 0;
while (<>) {
$sum_p += $_ for /(?<![\-\d.\/])\d+(?![\d\/])(?!\.\d)/g;
$sum_n += $_ for /-\d+(?!\d)(?!\.\d)/g;
++$dates while /\d{2}\/\d{2}\/\d{4}/g;
}
print "$sum_p\n";
print "$sum_n\n";
print "$dates\n";

how do you select column from a text file using perl

I want to subtract values in one column from another column and add the differences.How do I do this in perl? I am new to perl.Hence I am unable to figure out how to go about it. Kindly help me.
The first thing is to separate the data into columns. In this case, the columns are separated by a space. split(/ /) will return a list of the columns.
To subtract one from the other, its pulling the values out of the the list and subtracting them.
At the end, you add the difference to the running sum and then loop over the data.
#!/usr/bin/perl
use strict;
my $sum = 0;
while(<DATA>) {
my #vals = split(/ /);
my $diff = $vals[1] - $vals[0];
$sum += $diff;
}
print $sum,"\n";
__DATA__
1 3
3 5
5 7
This will print out 6 --- (3 - 1) + (5 - 3) + (7 - 5)
FYI, if you combine the autosplit (-a), loop (n) and command-line program (-e) arguments (see perlrun), you can shorten this to a one-liner, much like awk:
perl -ane "$sum += $F[1] - $F[0]; END { print $sum }" filename

Sum of tagged lines perl/shellscript

I have input that looks like
5 X
8 Y
3 Z
9 X
I want output that sums the numerical values for each 'tag'; e.g.
14 X
8 Y
3 Z
Wondering if there is a slick one liner I can use (along the lines of the ones for summing a list of integers using awk).
Something like this should do the trick:
perl -ne '$table{$2} += $1 if /(\d+)\s+(.+)/; END {print "$table{$_} $_\n" for keys %table}'
or to use auto-splitting:
perl -ane '$table{$F[1] or next} += $F[0]; END {print "$table{$_} $_\n" for keys %table}'
As slick as I can make it:
perl -alne 'END{print"$X{$_} $_"for sort{$X{$b}<=>$X{$a}}keys%X}$X{$F[1]}+=$F[0]'
Tried to make it as little obfuscated as possible :)
Sorts output by 'tag'.
perl -alne '$counts{$F[1]} += $F[0]; END { print "$counts{$_} $_" for sort(keys %counts) }'
Output in random order
perl -alne'$t{$F[1]}+=$F[0]}{print"$t{$_} $_"for keys%t'
alphabetically sorted by tag
perl -alne'$t{$F[1]}+=$F[0]}{print"$t{$_} $_"for sort keys%t'
sorted by value
perl -alne'$t{$F[1]}+=$F[0]}{print"$t{$_} $_"for sort{$t{$b}<=>$t{$a}}keys%t'
gawk "{count[$2]+=$1}END{for(i in count)print count[i],i}" 1.t