Problem using unshift to assign to a variable - arrays

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://';

Related

Indexing perl array

I have below code
#ar1 = ('kaje','beje','ceje','danjo');
$m = 'kajes';
my($next) = grep $_ eq 'kaje',#ar1;
print("Position is $next\n");
print("Next is $ar1[$next+1]\n");
print("Array of c is $ar1[$m+3]\n");
print("Array at m is $ar1[$m]\n");
Output seen:
Position is kaje
Next is beje
Array of c is danjo
Array at m is kaje
I want to understand how this works. Here $next is the matched string and i am able to index on that string for given array. Also $m is not found in the array, yet we get output as first element of array.
ALWAYS use use strict; use warnings;. It answers your question.
In one place, you treat the string kaje as a number.
In two places, you treat the string kajes as a number.
Since these two strings aren't numbers, Perl will use zero and issue a warning.
In other words, Next is beje only "works" because kaje happens to be at index 0. I have no idea how why you believe the last two lines work seeing as kajes is nowhere in the array.
You want
# Find the index of the element with value `kaje`.
my ($i) = grep $ar1[$_] eq 'kaje', 0..$#ar1;

Not able to divide each row of a csv file in the form of array using perl

I am stucked in a problem wherein I am parsing a csv file. The CSV file looks like-
CPU Name,DISABLE,Memory,Encoding,Extra Encoding
,b,d,,
String1,YES,1TB,Enabled,Enabled
String2,NO,1TB,Enabled,Enabled
String3,YES,1TB,Enabled,Enabled
I want to capture the first two rows in two different arrays. The code that I am using to do it is-
my $row_no =0;
while(my $row=<$fi>){
chomp($row);
$row=~ s/\A\s+//g;
$row=~s/\R//g;
#say $row;
if($row_no==0)
{
#say $row;
my #name_initial = split(',',$row);
say length(#name_initial);
say #name_initial;
}
elsif($row_no==1)
{
#say $row;
#data_type_initial =split(',',$row);
say length(#data_type_initial);
say #data_type_initial;
}
$row_no++;
}
Now I formed two arrays from topmost two lines in file (#name_initial and #data_type_initial respectively).When I am printing these array I can see all the 5 values but when I am printing the length of array it is showing length of each array as 1. When I am printing the element using index of arrays I find each element in place then why it is showing length as 1. Also second array which is formed from second line of csv file is printed as "bd". All the null values are gone and although it is containing two values 'b' and 'd'. Its length is printed as 1.
I want to convert the row of csv file in array with all the null and non_NULL values so that I can iterate on the array elements and can give conditions based on null and non null values.How can I do that???
Have a look at perldoc length. It says this:
length EXPR
length
Returns the length in characters of the value of
EXPR. If EXPR is omitted, returns the length of $_. If EXPR is
undefined, returns undef.
This function cannot be used on an entire array or hash to find out
how many elements these have. For that, use scalar #array and scalar
keys %hash, respectively.
Like all Perl character operations, length normally deals in logical
characters, not physical bytes. For how many bytes a string encoded as
UTF-8 would take up, use length(Encode::encode('UTF-8', EXPR)) (you'll
have to use Encode first). See Encode and perlunicode.
In particular, the bit that says "This function cannot be used on an entire array or hash to find out how many elements these have. For that, use scalar #array and scalar keys %hash, respectively".
So you're using the wrong approach here. Instead of say length(#array), you need say scalar(#array).
To explain the results you're getting. length() expects to be given a scalar value (a string) to measure. So it treats your array as a scalar (effectively adding an invisible call to scalar()) and gets back the number of elements in the array (which is "5") and length() then tells you the number of elements in that string - which is 1.
It's also worth pointing out that you don't need to keep track of your own $row_no variable. Perl has a built-in variable called $. which contains the current record number.
Using that knowledge (and adding little whitespace) gives us something like this:
while (my $row = <$fi>) {
chomp($row);
$row =~ s/\A\s+//g;
$row =~s/\R//g;
#say $row;
if ($. == 0) {
#say $row;
my #name_initial = split(/,/, $row);
say scalar(#name_initial);
say #name_initial;
} elsif ($. == 1) {
#say $row;
#data_type_initial = split(/,/, $row);
say scalar(#data_type_initial);
say #data_type_initial;
}
}
Update: You sneaked a couple of extra questions in at the end of this one. I'd suggest that you raise those separately.

Perl array reference always rewrites over itself in a loop

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;.

Adding regex to an array in Perl

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";

How to get a single column of emails from a html textarea into array

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.

Resources