I load some variables from the URL and want to check in my CGI script whether are they initialized. I quickly found out that I can not put uninitialized values into an list in Perl.
My approach was simply to iterate through the list and use a switch variable $sucessDOM (1 if all data had been initialized and 0 elsewhere).
I came up with this:
### Read data from HTML
my $mailinglist = param( 'mailinglist' );
my $firstname = param( 'firstname' );
my $lastname = param( 'lastname' );
my $mail = param( 'mail' );
my $sucessDOM = 0;
my #DOM = { $mailinglist, $firstname, $lastname, $mail };
### Data validation
for my $data ( #DOM ) {
if ( $data eq undef ) {
$sucessDOM = $sucessDOM + 1;
}
if ( $sucessDOM = #DOM ) {
print "#DOM\n";
$sucessDOM = 1;
}
else {
$sucessDOM = 0;
}
}
The output is as follows
[Fri Dec 22 20:30:40 2017] read_form.cgi: Use of uninitialized value $mailinglist in anonymous hash ({}) at ./read_form.cgi line 20.
[Fri Dec 22 20:30:40 2017] read_form.cgi: Use of uninitialized value $lastname in anonymous hash ({}) at ./read_form.cgi line 20.
[Fri Dec 22 20:30:40 2017] read_form.cgi: Use of uninitialized value in string eq at ./read_form.cgi line 24.
HASH(0x55c8a73eeea8)
I also cannot understand why are there errors for only two values in the array if they are all uninitialized, as I run the script directly without passing any values.
You have at least four problems with your code:
First, {} makes an anonymous hash and returns a reference to it; this is a single value that ends up in #DOM. The warnings are because hash keys have to be strings, and warn if they are undef. You should be assigning like
my #DOM = ( $mailinglist, $firstname, $lastname, $mail );
Second, eq compares strings, so it would convert undef to ''. To test if $data is undef, do
if (! defined $data) {
Third, you are checking if all the array elements were successful inside the for loop (where that will not be true on any but the last iteration of the loop). Move the if ($successDOM... block to after the for loop.
Fourth, = is just an assignment operator; use == for numeric comparison:
if ($successDOM == #DOM) {
Related
I can't understand the proposed solutions in other questions or resolve the php error Uninitialized string offset: 0 .
I used this code to create acronyme from a string
$article = 'the Central intelligence agency';
$words = array('the', 'of', 'to' );
$pattern = '/\b(?:' . join('|', $words) . ')\b/i';
$entityWords = preg_replace($pattern, '', $article);
$words = explode(" ", $entityWords);
var_dump($words);
$entityAcro = "";
foreach ($words as $letter) {
-> $entityAcro .= $letter[0];
}
echo strtoupper( $entityAcro );
I get this result :
Notice: Uninitialized string offset: 0 ....line (->)
Notice: Uninitialized string offset: 0 ....line (->)
CIA
I don't understand this solution : "you must know if it exist (isset)"
I manage multiple organizations and I can't know before how many word there are inside string.
Issue resolved with this solution:
foreach ($words as $letter) {
if(!empty($letter[0])){
$entityAcro .= $letter[0];
}
}
I had to verify the existence of each word $letter[0] in the array before showing the result of the foreach condition
I need to evaluate a series of strings that I want to convert into a hash of arrays. Take into account that, in this case, I want to add an array to an entry in a hash that it is already storing an array. I need to get the following hash:
ConfigurationHash{'Editor'} = (John, Mary, Jane, Peter)
I have stripped down my code to this example:
use strict;
use warnings;
my %ConfigurationHash;
my $String1 = "Editor=John,Mary";
my $String2 = "Editor=Jane,Peter";
my #Line1 = split ("=", $String1);
my #Line2 = split ("=", $String2);
my $Variable1 = #Line1[0];
my $Value1 = #Line1[1];
my $Variable2 = #Line2[0];
my $Value2 = #Line2[1];
my #Values1Array = split(",", $Value1);
my #Values2Array = split(",", $Value2);
if ( ! exists $ConfigurationHash{$Variable1} ) {
$ConfigurationHash{$Variable1} = #Values1Array;
}
else {
push (#ConfigurationHash{$Variable1}, #Values1Array);
}
which produces the following error:
Experimental push on scalar is now forbidden at ./test.pl line 25, near "#Values1Array)"
Execution of ./test.pl aborted due to compilation errors.
I know that the problem lies in references/dereferences, but my knowledge of perl is so basic that I'm not able to figure how to get there by myself.
Could anybody show me how to do it? I would also appreciate if you could show me how to iterate the values of the array in the hash once it is created.
It's unclear why you have $String2 and its derivatives in your code as they are never used. This code processes both strings
You simply need to push the list of values to the array corresponding to $Variable1 (dreadful choice of identifier) in the hash. Accomplish this by dereferencing the array element
use strict;
use warnings;
my %config;
my $s1 = 'Editor=John,Mary';
my $s2 = 'Editor=Jane,Peter';
for ( $s1, $s2 ) {
my ($key, #values) = split /[=,]/;
push #{ $config{$key} }, #values;
}
use Data::Dumper;
print Dumper \%config;
output
$VAR1 = {
'Editor' => [
'John',
'Mary',
'Jane',
'Peter'
]
};
This line isn't doing what you think it does.
$ConfigurationHash{$Variable1} = #Values1Array;
If you printed out what $ConfigurationHash{$Variable1} contains you'll find it only contains the size of #Values1Array.
You should be fine to use push but with a slight modification to what you've written.
push #{$ConfigurationHash{$Variable1}}, #Values1Array;
I've also removed the brackets as you don't need them.
As for iterating over the array, it is no different to iterating over a regular array. You were likely having problems iterating over it before as you didn't have an array
foreach my $whatever (#{$ConfigurationHash{$Variable1}})
{
# Code
}
Thank you to all who posted answers. #Borodin, you're right, I missed a second block that used $String2 and its derivatives, but I think it was obvious it was at the end and was similar to the if-else block in my original code.
Thank you, #chris-turner, for giving me the hint on how to use push the right way and pointing out the error in the $ConfigurationHash{$Variable1} = #Values1Array;
With all these contributions I figured out that the right code I was expecting is:
use strict;
use warnings;
my %ConfigurationHash;
my $String1 = "Editor=John,Mary";
my $String2 = "Editor=Jane,Peter";
my #Line1 = split ("=", $String1);
my #Line2 = split ("=", $String2);
my $Variable1 = $Line1[0];
my $Value1 = $Line1[1];
my $Variable2 = $Line2[0];
my $Value2 = $Line2[1];
my #Values1Array = split(",", $Value1);
my #Values2Array = split(",", $Value2);
if ( ! exists $ConfigurationHash{$Variable1} ) {
$ConfigurationHash{$Variable1} = \#Values1Array;
}
else {
#push (#ConfigurationHash{$Variable1}, #Values1Array);
push #{$ConfigurationHash{$Variable1}}, #Values1Array;
}
if ( ! exists $ConfigurationHash{$Variable2} ) {
$ConfigurationHash{$Variable2} = \#Values2Array;
}
else {
#push (#ConfigurationHash{$Variable2}, #Values2Array);
push #{$ConfigurationHash{$Variable2}}, #Values2Array;
}
use Data::Dumper;
print Dumper \%ConfigurationHash;
Which outputs the following:
$VAR1 = {
'Editor' => [
'John',
'Mary',
'Jane',
'Peter'
]
};
I have problem with accessing a hash in each element of array after creating it but it gave the last element. What should I do to access all the elements of my array?
#stem = ();
for($i=0;$i<2;++$i){
push #stem,{u1=>1 , u2 => 2 , u3 => 3};
}
#ants = ();
$count = 0;
for($i=0;$i<scalar(#stem);++$i){
#allowed = ();
%hash = ();
for($j=0;$j<scalar(#stem);++$j){
push #allowed,{stem=>++$count,hinfo=>++$count};
}
%hash = ( allowed=>\#allowed ,solution=>++$count);
push (#ants,\%hash);
}
for($i=0;$i<scalar(#ants);++$i){
%test = %{$ants[$i]};
print "=>",$test{solution},"\n";
#temp = #{$test{allowed}};
for($j=0;$j<scalar(#temp);++$j){
print $j,":",$temp[$j]->{stem}," ",$temp[$j]->{hinfo},"\n";
}
}
output:
=>21
0:16 16
1:18 18
2:20 20
=>21
0:16 16
1:18 18
2:20 20
Since there is just one variable #allowed and one variable %hash, where you take references to them you are always getting the same value (which was cleared and set in the final iteration of the loop).
Declare them inside the loop, and you will be get references to new variables each time through the loop:
for($i=0;$i<scalar(#stem);++$i){
my #allowed;
my %hash;
for($j=0;$j<scalar(#stem);++$j){
push #allowed,{stem=>++$count,hinfo=>++$count};
}
%hash = ( allowed=>\#allowed ,solution=>++$count);
push (#ants,\%hash);
}
I want to use an expression like
#{ %$hashref{'key_name'}[1]
or
%$hashref{'key_name}->[1]
to get - and then test - the second (index = 1) member of an array (reference) held by my hash as its "key_name" 's value. But, I can not.
This code here is correct (it works), but I would have liked to combine the two lines that I have marked into one single, efficient, perl-elegant line.
foreach my $tag ('doit', 'source', 'dest' ) {
my $exists = exists( $$thisSectionConfig{$tag});
my #tempA = %$thisSectionConfig{$tag} ; #this line
my $non0len = (#tempA[1] =~ /\w+/ ); # and this line
if ( !$exists || !$non0len) {
print STDERR "No complete \"$tag\" ... etc ... \n";
# program exit ...
}
I know you (the general 'you') can elegantly combine these two lines. Could someone tell me how I could do this?
This code it testing a section of a config file that has been read into a $thisSectionConfig reference-to-a-hash by Config::Simple. Each config file key=value pair then is (I looked with datadumper) held as a two-member array: [0] is the key, [1] is the value. The $tag 's are configuration settings that must be present in the config file sections being processed by this code snippet.
Thank you for any help.
You should read about Arrow operator(->). I guess you want something like this:
foreach my $tag ('doit', 'source', 'dest') {
if(exists $thisSectionConfig -> {$tag}){
my $non0len = ($thisSectionConfig -> {$tag} -> [1] =~ /(\w+)/) ;
}
else {
print STDERR "No complete \"$tag\" ... etc ... \n";
# program exit ...
}
I have an AoA construct with four columns and many rows. Following is an example of data (input).
DQ556929 103480190 103480214 154943
DQ540839 103325247 103325275 2484
DQ566549 103322763 103322792 99
DQ699634 103322664 103322694 0
DQ544472 103322664 103322692 373
DQ709105 103322291 103322318 46
DQ705937 103322245 103322273 486
DQ699398 103321759 103321788 1211
DQ710151 103320548 103320577 692251
DQ548430 102628297 102628326 1
DQ558403 102628296 102628321 855795
DQ692476 101772501 101772529 481463
DQ544274 101291038 101291068 484047
DQ723982 100806991 100807020 1
DQ709023 100806990 100807020 3
DQ712307 100806987 100807014 0
DQ709654 100806987 100807012 571051
DQ707370 100235936 100235962 1481849
I want to group and write into a file all the row elements (sequentially).
Conditions are if column four values less than 1000 and minimum two values are next to each other, group them else if the value less than 1000 and lies between the values more than 1000 treat them as single and append separately in the same file and the values which are more than 1000 also write as a block but with out affecting the order of the 2nd and third column.
This file is output of my previous program, now for this I have tried implementing my hands but getting some weird results. Here is my chunk of code, but non functional. Guys I need just help if i am executing my logic well here, I am open for any comments as a beginner. And also correct me anywhere.
my #dataf= sort{ $a->[1]<=> $b->[1]} #data;
#dataf=reverse #dataf;
for(my $i>=0;$i<=$#Start;$i++)
{
print "$sortStart[$i]\n";
my $diff = $sortStart[$i] - $sortStart[$i+1];
$dataf[$i][3]= $diff;
# $IDdiff{$ID[$i]}=$diff;
}
#print Dumper(#dataf);
open (CLUST, ">> ./clustTest.txt" );
for (my $k=0;$k<=$#Start;$k++)
{
for (my $l=0;$l<=3;$l++)
{
# my $tempdataf = shift $dataf[$k][$l];
# print $tempdataf;
if ($dataf[$k][3]<=1000)
{
$flag = 1;
do
{
print CLUST"----- Cluster $clustNo -----\n";
print CLUST"$dataf[$k][$l]\t";
if ($dataf[$k][3]<=1000)
{
$flag1 = 1;
}else {$flag1=0;}
$clustNo++;
}until($flag1==0 && $data[$k][3] > 1000);
if($flag1==0 && $data[$k][3] > 1000)
{
print CLUST"Singlet \n";
print CLUST"$dataf[$k][$l]\t";
next;
}
#print CLUST"$dataf[$k][$l]\t"; ##IDdiff
}
print CLUST"\n";
}
}
Expected output in file:
Singlets
DQ556929 103480190 103480214 154943
DQ540839 103325247 103325275 2484
Cluster1
DQ566549 103322763 103322792 99
DQ699634 103322664 103322694 0
DQ544472 103322664 103322692 373
DQ709105 103322291 103322318 46
DQ705937 103322245 103322273 486
Singlets
DQ699398 103321759 103321788 1211
DQ710151 103320548 103320577 692251
DQ548430 102628297 102628326 1
DQ558403 102628296 102628321 855795
DQ692476 101772501 101772529 481463
DQ544274 101291038 101291068 484047
Cluster2
DQ723982 100806991 100807020 1
DQ709023 100806990 100807020 3
DQ712307 100806987 100807014 0
Singlets
DQ709654 100806987 100807012 571051
DQ707370 100235936 100235962 1481849
This seems to produce the expected output. I'm not sure I understood the specification correctly, so there might be errors and edge cases.
How it works: it remembers what kind of section it's currently outputting ($section, Singlet or Cluster). It accumulates lines in the #cluster array if they belong together, when an incompatible line arrives, the cluster is printed and a new one is started. If the cluster to print has only one member, it's treated as a singlet.
#!/usr/bin/perl
use warnings;
use strict;
my $section = q();
my #cluster;
my $cluster_count = 1;
sub output {
if (#cluster > 1) {
print "Cluster$cluster_count\n";
$cluster_count++;
} elsif (1 == #cluster) {
print $section = 'Singlet', "s\n" unless 'Singlet' eq $section;
}
print for #cluster;
#cluster = ();
}
my $last = 'INF';
while (<>) {
my ($id, $from, $to, $value) = split;
if ($value > 1000 || 1000 < abs($last - $from)) {
output();
} else {
$section = 'Cluster';
}
push #cluster, $_;
$last = $to;
}
output();