I've just started using PERL for some scripting i'm doing, having never used it before, and I'm having some trouble getting some values into an array, and calculating the total.
I have a log file that i want to parse, and using a regex, pick up when certain values appear. i want these values added to an array, and then the total calculated at the end.
The file I'm trying to parse looks like
...completed_pop_count: 0
...uncompleted: 0
CALL NEXT
...completed_pop_count: 2
...uncompleted: 0
CALL NEXT
...completed_pop_count: 2
...uncompleted: 3
CALL NEXT
....and carries on
This is what i have so far:
open (my $file, 'test.log');
while (<$file>){
my #array = /.*completed_pop_count: (.*)$/;
print #array;
}
close($file);
The output to this is like
022.....
To me this looks like all the values are in a single element of the array. However I need them to be on separate so that I can calculate the total sum.
If you want to add elements to array, use push #arr, "element".
use List::Util qw(sum);
my #array;
while (<$file>){
push #array, $1 if /.*completed_pop_count: (.*)$/;
}
print "#array\n";
print sum(#array), "\n";
Related
i have an array which contents elements in which some elements are similiar under certain conditions (if we detete the "n and p" from the array element then the similiar element can be recognised) . I want to use these similiar element at once while using foreach statement. The array is seen below
my #array = qw(abc_n abc_p gg_n gg_p munday_n_xy munday_p_xy soc_n soc_p);
Order of the array element need not to be in this way always.
i am editing this question again. Sorry if i am not able to deliver the question properly. I have to print a string multiple times in the file with the variable present in the above array . I am just trying to make you understand the question through below code, the below code is not right in any sense .... i m just using it to make you understand my question.
open (FILE, ">" , "test.v");
foreach my $xy (#array){
print FILE "DUF A1 (.pin1($1), .pin2($2));" ; // $1 And $2 is just used to explain that
} // i just want to print abc_n and abc_p in one iteration of foreach loop and followed by other pairs in successive loops respectively
close (FILE);
The result i want to print is as follows:
DUF A1 ( .pin1(abc_n), .pin2(abc_p));
DUF A1 ( .pin1(gg_n), .pin2(gg_p));
DUF A1 ( .pin1(munday_n_xy), .pin2(munday_p_xy));
DUF A1 ( .pin1(soc_n), .pin2(soc_p));
The scripting language used is perl . Your help is really appreciated .
Thank You.!!
Partitioning a data set depends entirely on how data are "similiar under certain conditions."
The condition given is that with removal of _n and _p the "similar" elements become equal (I assume that underscore; the OP says n and p). In such a case one can do
use warnings;
use strict;
use feature 'say';
my #data = qw(abc_n abc_p gg_n gg_p munday_n_xy munday_p_xy soc_n soc_p);
my %part;
for my $elem (#data) {
push #{ $part{ $elem =~ s/_(?:n|p)//r } }, $elem;
}
say "$_ => #{$part{$_}}" for keys %part;
The grouped "similar" strings are printed as a demo since I don't understand the logic of the shown output. Please build your output strings as desired.
If this is it and there'll be no more input to process later in code, nor will there be a need to refer to those common factors, then you may want the groups in an array
my #groups = values %part;
If needed throw in a suitable sorting when writing the array, sort { ... } values %part.
For more fluid and less determined "similarity" try "fuzzy matching;" here is one example.
I tried to split one string and assign an array, and then add http at the start using unshift.
But, I am not getting the desired output. What am I doing wrong here?
use strict;
my $str = 'script.spoken-tutorial.org/index.php/Perl';
my #arr = split (/\//,$str);
print "chekcing the split function:\n #arr\n";
my #newarr = unshift(#arr, 'http://');
print "printing new array: #newarr\n";
the output is:
checking the split function:
script.spoken-tutorial.org index.php Perl
printing new array: 4
Why instead of adding http is it giving number 4 (which is array length)?
This is documented behaviour. From perldoc -f unshift:
unshift ARRAY,LIST
Does the opposite of a shift. Or the opposite of a push, depending on how you look at it. Prepends list to the front of the array and
returns the new number of elements in the array.
See the bolded last part. This means the return value of the function unshift() is the size of the array. Which is what you did.
unshift(#arr, 'http://'); # this returns 4
What you want is to do either
my #newarr = ('http://', #arr);
Or
my #newarr = #arr;
unshift #newarr, 'http://';
I am trying to read some numbers from a text file and store it as a 2 dimensional array. I read a line and push into another array as an array reference. But I noticed that main array only has last line in all rows. How can i correct this? Thanks in advance. This is part i do it.
open IN, "a.txt";
#b=();
while (<IN>)
{
$t =$_;
#a = split /\s+/,$t;
push(#b, \#a);
}
You only have only two arrays in total. You want one per line, plus #b. my creates a new variable each time it is executed, so you can use the following:
my #b;
while (<IN>) {
my #a = split;
push #b, \#a;
}
By the way, you should always use use strict; use warnings;.
I'm developing a Perl script and one of the script functions is to detect many lines of data between two terminals and store them in an array. I need to store all lines in an array but to be grouped separately as 1st line in $1 and 2nd in $2 and so on. The problem here is that number of these lines is variable and will change with each new run.
my #statistics_of_layers_var;
for( <ALL_FILE> ) {
#statistics_of_layers_var = ($all_file =~ /(Statistics\s+Of\s+Layers)
(?:(\n|.)*)(Summary)/gm );
print #statistics_of_layers_var;
The given data should be
Statistics Of Layers
Line#1
Line#2
Line#3
...
Summary
How I could achieve it?
You can achieve this without a complicated regular expression. Simply use the range operator (also called flip-flop operator) to find the lines you want.
use strict;
use warnings;
use Data::Printer;
my #statistics_of_layers_var;
while (<DATA>) {
# use the range-operator to find lines with start and end flag
if (/^Statistics Of Layers/ .. /^Summary/) {
# but do not keep the start and the end
next if m/^Statistics Of Layers/ || m/^Summary/;
# add the line to the collection
push #statistics_of_layers_var, $_ ;
}
}
p #statistics_of_layers_var;
__DATA__
Some Data
Statistics Of Layers
Line#1
Line#2
Line#3
...
Summary
Some more data
It works by looking at the current line and flipps the block on and off. If /^Statistics of Layers/ matches the line it will run the block for each following line until the `/^Summary/ matches a line. Because those start and end lines are included we need to skip them when adding lines to the array.
This also works if your file contains multiple intances of this pattern. Then you'd get all of the lines in the array.
Maybe you can try this :
push #statistics_of_layers_var ,[$a] = ($slurp =~ /(Statistics\s+Of\s+Layers)
(?:(\n|.)*)(Summary)/gm );
I was thinking I could do this on my own but I need some help.
I need to paste a list of email addresses from a local bands mail list into a textarea and process them my Perl script.
The emails are all in a single column; delimited by newlines:
email1#email.com
email2#email.com
email3#email.com
email4#email.com
email5#email.com
I would like to obviously get rid of any whitespace:
$emailgoodintheory =~ s/\s//ig;
and I am running them through basic validation:
if (Email::Valid->address($emailgoodintheory)) { #yada
I have tried all kinds of ways to get the list into an array.
my $toarray = CGI::param('toarray');
my #toarraya = split /\r?\n/, $toarray;
foreach my $address(#toarraya) {
print qq~ $address[$arrcnt]<br /> ~:
$arrcnt++;
}
Above is just to test to see if I was successful. I have no need to print them.
It just loops through, grabs the schedules .txt file and sends each member the band schedule. All that other stuff works but I cannot get the textarea into an array!
So, as you can see, I am pretty lost.
Thank you sir(s), may I have another quick lesson?
You seem a bit new to Perl, so I will give you a thorough explanation why your code is bad and how you can improve it:
1 Naming conventions:
I see that this seems to be symbolic code, but $emailgoodintheory is far less readable than $emailGoodInTheory or $email_good_in_theory. Pick any scheme and stick to it, just don't write all lowercase.
I suppose that $emailgoodintheory holds a single email address. Then applying the regex s/\s//g or the transliteration tr/\s// will be enough; space characters are not case sensitive.
Using a module to validate adresses is a very good idea. :-)
2 Perl Data Types
Perl has three man types of variables:
Scalars can hold strings, numbers or references. They are denoted by the $ sigil.
Arrays can hold an ordered sequence of Scalars. They are denoted by the # sigil.
Hashes can hold an unordered set of Scalars. Some people tend to know them as dicitonaries. All keys and all values must be Scalars. Hashes are denoted by the % sigil.
A word on context: When getting a value/element from a hash/array, you have to change the sigil to the data type you want. Usually, we only recover one value (which always is a scalar), so you write $array[$i] or $hash{$key}. This does not follow any references so
my $arrayref = [1, 2, 3];
my #array = ($arrayref);
print #array[0];
will not print 123, but ARRAY(0xABCDEF) and give you a warning.
3 Loops in Perl:
Your loop syntax is very weird! You can use C-style loops:
for (my $i = 0; $i < #array; $i++)
where #array gives the length of the array, because we have a scalar context. You could also give $i the range of all possible indices in your array:
for my $i (0 .. $#array)
where .. is the range operator (in list context) and $#array gives the highest available index of our array. We can also use a foreach-loop:
foreach my $element (#array)
Note that in Perl, the keywords for and foreach are interchangeable.
4 What your loop does:
foreach my $address(#toarraya) {
print qq~ $address[$arrcnt]<br /> ~:
$arrcnt++;
}
Here you put each element of #toarraya into the scalar $address. Then you try to use it as an array (wrong!) and get the index $arrcnt out of it. This does not work; I hope your program died.
You can use every loop type given above (you don't need to count manually), but the standard foreach loop will suit you best:
foreach my $address (#toarraya){
print "$address<br/>\n";
}
A note on quoting syntax: while qq~ quoted ~ is absolutely legal, this is the most obfuscated code I have seen today. The standard quote " would suffice, and when using qq, try to use some sort of parenthesis (({[<|) as delimiter.
5 complete code:
I assume you wanted to write this:
my #addressList = split /\r?\n/, CGI::param('toarray');
foreach my $address (#addressList) {
# eliminate white spaces
$address =~ s/\s//g;
# Test for validity
unless (Email::Valid->address($address)) {
# complain, die, you decide
# I recommend:
print "<strong>Invalid address »$address«</strong><br/>";
next;
}
print "$address<br/>\n";
# send that email
}
And never forget to use strict; use warnings; and possibly use utf8.