I am posting this for the 1st time. I have gone through similar issues in the forum, but still I am not able to determine why I am getting this error.
Here is a sample code which I am trying to make..
use strict;
use warnings;
my ($m, $b) = #ARGV;
my $count_args = $#ARGV + 1;
my $times = 2**$m;
main();
sub main {
if ( $m =~ /^\d+$/ ) {
if ( $b =~ /^and$/i ) {
func_and();
} else {
print " not supported\n";
}
} else {
print " enter valid number of pins\n";
}
}
sub func_and {
my $bit;
for ( my $i = 0 ; $i < $times ; $i++ ) {
my $p = sprintf( "%0${m}b", $i );
print "$p\t";
my #c = split( '', $p );
my $result = 3;
foreach $bit (#c) {
if ( $result < 3 ) {
$result = $result && $bit;
} else {
$result = $bit;
}
}
print "result for AND operation on $bit is $result \n";
}
}
if i give the input as perl AND.pl 2 and
The error I get is Use of uninitialized value in concatenation (.) or string at NAND.pl line 34.
is there any other way to declare the $ bit variable? and how can one initialize this?
Thanks
Change:
print "result for AND operation on $bit is $result \n";
to:
print "result for AND operation on $p is $result \n";
Then, you can localize $bit to the foreach loop:
foreach my $bit (#c) {
perldoc perlsyn:
The foreach loop iterates over a normal list value and sets the
variable VAR to be each element of the list in turn. If the variable
is preceded with the keyword my, then it is lexically scoped, and is
therefore visible only within the loop. Otherwise, the variable is
implicitly local to the loop and regains its former value upon exiting
the loop.
If the variable was previously declared with my, it uses that variable
instead of the global one, but it's still localized to the loop.
$bit was uninitialized before the loop, so it is still unchanged after the loop.
The worst solution to this problem is to assign a value to $bit when you declare it.
my $bit = 0; # no!!!
While this gets around the error message it makes it difficult to find the logical error in your code. The warning message "use of uninitialized value..." is one of the most important debugging tools you have. If your code produces many such messages, you should turn your warnings into errors so the program halts at the first warning.
use warnings 'FATAL' => 'all';
Related
I have a Perl script in which I perform web service calls in a loop. The server returns a multivalued HTTP header that I need to parse after each call with information that I will need to make the next call (if it doesn't return the header, I want to exit the loop).
I only care about one of the values in the header, and I need to get the information out of it with a regular expression. Let's say the header is like this, and I only care about the "foo" value:
X-Header: test-abc12345; blah=foo
X-Header: test-fgasjhgakg; blah=bar
I can get the header values like this: #values = $response->header( 'X-Header' );. But how do I quickly check if
There is a foo value, and
Parse and save the foo value for the next iteration?
Ideally, I'd like to do something like this:
my $value = 'default';
do {
# (do HTTP request; use $value)
#values = $response->header( 'X-Header' );
} while( $value = first { /(?:test-)([^;]+)(?:; blah=foo)/ } #values );
But grep, first (from List::Util), etc. all return the entire match and not just the single capturing group I want. I want to avoid cluttering up my code by looping over the array and matching/parsing inside the loop body.
Is what I want possible? What would be the most compact way to write it? So far, all I can come up with is using lookarounds and \K to discard the stuff I don't care about, but this isn't super readable and makes the regex engine perform a lot of unnecessary steps.
So it seems that you want to catch the first element with a certain pattern, but acquire only the pattern. And you want it done nicely. Indeed, first and grep only pass the element itself.
However, List::MoreUtils::first_result does support processing of its match
use List::MoreUtils 0.406 qw(first_result);
my #w = qw(a bit c dIT); # get first "it" case-insensitive
my $res = first_result { ( /(it)/i )[0] } #w;
say $res // 'undef'; #--> it
That ( ... )[0] is needed to put the regex in the list context so that it returns the actual capture. Another way would be firstres { my ($r) = /(it)/i; $r }. Pick your choice
For the data in the question
use warnings;
use strict;
use feature 'say';
use List::MoreUtils 0.406 qw(firstres);
my #data = (
'X-Header: test-abc12345; blah=foo',
'X-Header: test-fgasjhgakg; blah=bar'
);
if (my $r = firstres { ( /test-([^;]+);\s+blah=foo/ )[0] } #data) {
say $r
}
Prints abc12345, clarified in a comment to be the sought result.
Module versions prior to 0.406 (of 2015-03-03) didn't have firstres (alias first_result)
first { ... } #values returns one the values (or undef).
You could use either of these:
my ($value) = map { /...(...).../ } #values;
my $value = ( map { /...(...).../ } #values ) ? $1 : undef;
my $value = ( map { /...(...).../ } #values )[0];
Using first, it would look like the following, which is rather silly:
my $value = first { 1 } map { /...(...).../ } #values;
However, assuming the capture can't be an empty string or the string 0, List::MoreUtils's first_result could be used to avoid the unnecessary matches:
my $value = first_result { /...(...).../ ? $1 : undef } #values;
my $value = first_result { ( /...(...).../ )[0] } #values;
If the returned value can be false (e.g. an empty string or a 0) you can use something like
my $value = first_result { /...(...).../ ? \$1 : undef } #values;
$value = $$value if $value;
The first_result approach isn't necessarily faster in practice.
Following code snippet is looking for foo stored in a variable $find, the found values is stored in variable $found.
my $find = 'foo';
my $found;
while( $response->header( 'X-Header' ) ) {
if( /X-Header: .*?blah=($find)/ ) {
$found = $1;
last;
}
}
say $found if $found;
Sample demo code
use strict;
use warnings;
use feature 'say';
use Data::Dumper;
my $find = 'foo';
my $found;
my #header = <DATA>;
chomp(#header);
for ( #header ) {
$found = $1 if /X-Header: .*?blah=($find)/;
last if $found;
}
say Dumper(\#header);
say "Found: $found" if $found;
__DATA__
X-Header: test-abc12345; blah=foo
X-Header: test-fgasjhgakg; blah=bar
Output
$VAR1 = [
'X-Header: test-abc12345; blah=foo',
'X-Header: test-fgasjhgakg; blah=bar'
];
Found: foo
The below code is giving an error when I use if-else block for the comparison of $valid. When if-else condition is not used the error is not there. The error is " Use of uninitialized value $value in regexp compilation".How to solve this?
...
if($valid eq 1){
print "Enter value\n" ;
my $value = <STDIN>;
}else{
print " valid is not 1 \n";
}
if($line =~ /$string.*$value/){ --> error
//code
}
Perl program needs (pragma: A pragma is a module which influences some aspect of the compile time or run time behaviour of Perl, such as strict or warnings). Unless until we see the full code.
Please understand the declaration of the variables inside the block and outside of the block.
Coming to your code:
if($valid eq 1)
{
print "Enter value\n" ;
my $value = <STDIN>;
#This the "$value" prints what you have get from the MS-Dos Prompt from the user.
#$value ends here since the $value has been declared this block
}
$value needs to declare outside the if-else block you won't get the error message.
my $value = "";
if($valid eq 1)
{
print "Enter value\n" ;
$value = <STDIN>;
chomp($value); #Additionally, you should chomp (remove the entermark at end of the value $value;
}
Thanks.
I took some liberty to alter your code to make it work
[enter dog or cat at the prompt for a test]
use strict;
use warnings;
my $valid = '1';
my $value;
my $line = 'Some lazy dog is taking a sun bath';
my $string = 'lazy';
if($valid eq '1'){
print "Enter value: " ;
$value = <STDIN>;
chomp $value;
}else{
print " valid is not 1 \n";
}
if( $line =~ /$string.*$value/ ){
print 'Horay!!! I found the string - ';
print "$line\n";
} else {
print "Sorry, no line found\n";
}
Your error is hidden in scope declaration of $value -- it is only valid for if internal block of code - I have moved it outside of if ... else ... block.
NOTE: perhaps you intended to write
my $valid = 1;
....
if( $valid ) {
....
} else {
....
}
although the following code is valid but in this particular case is excessive (if $valid is not zero it considered true)
if( $valid == 1 ) {
....
} else {
....
}
Comparison operators for numbers and strings
I don't know if you're allowed to ask questions about a school assignment. I just want to understand what I am supposed to do, not do this for me. Maybe I am missing something so simple it is right in front of me but anyways it was based off of an older assignment, but I had missed this class and I am running into a wall now, and well the problem is that I'm trying to push an array into a hash table. using something like this;
push #{$hash_table{$hash_key}}, $port
and to count the ports while storing them and then to print the contents of the hash
while ( ($key , $value) = each ( %hash ) ) {
print “$key scanned #{$value}”
}
and if I wanted to sort the results I would use
< foreach $key ( keys ( %hash ) ) {
}
The current code I have is this, searching for the string of /iNext-DROP/
using a log file provided. I cant for the life of me find the correct place to add the code above
use warnings;
my $LogRecord;
my $LogRecordCount;
open LOGFILE, "sample.log.txt" or die "couldn't open sample.log.txt";
while ($LogRecord = <LOGFILE>) {
if ($LogRecord =~ /INext-DROP/) {
$LogRecordCount ++;
$LogRecord =~ /(SRC=[0-9\.]* ).*(SPT=[0-9\.]* )/;
$source=$1;
$sport=$2;
print "$source$sport";
print substr( $LogRecord , 0 , $ARGV[1] ) , "\n" if $ARGV[1];
}
}
print "The file contained $LogRecordCount records" if $ARGV[1];
close LOGFILE;
Here's a picture of the old code with comments ;
Old Code -- not much has changed since I keep going back after it doesn't work
The thing you're seemingly having problems with, is that you're not sure where the port is being captured and the hash update.
What's happening is your while loop is iterating the file one line at a time, and capturing values - that $LogRecord =~ line is capturing a pattern - into $1 and $2.
And then that $2 is the thing you can add to your hash, with push.
However, there's a few things I have changed style wise like using lexical file handles because it's better style.
#!/usr/bin/env perl
use warnings;
use strict;
#because it makes debugging easier.
use Data::Dumper;
my $LogRecordCount;
#declare some hashes;
my %ports_from;
my %ips_that_used;
open my $logfile, "sample.log.txt" or die "couldn't open sample.log.txt";
while (my $line = <$logfile>) {
#matches 'current line' - skips stuff that doesn't match.
next unless $line =~ /INext-DROP/;
#increment count.
$LogRecordCount++;
my ( $source, $src_port ) = $line =~ m/SRC=([0-9\.]+).*SPT=([0-9]+)/;
print "$source$sport";
#not sure what this is doing, so I have left it in.
print substr( $line , 0 , $ARGV[1] ) , "\n" if $ARGV[1];
push #{$ports_from{$source}}, $src_port;
push #{$ips_that_used{$src_port}}, $source;
}
print "The file contained $LogRecordCount records" if $ARGV[1];
close $logfile;
print Dumper \%ports_from;
print Dumper \%ips_that_used;
That's built up your hashes.
But when it comes to outputing:
foreach my $ip ( keys %ports_from ) {
print "$ip: ", join ( " ", #{$ports_from{$ip}}) ,"\n"
}
If you wanted to sort them, you would have to do this using sort.
Now sort is a pretty clever function, but by default is sorts alphanumerically. That's ... actually not all that useful when it comes to IP addresses or port numbers, because you probably want to sort those more numerically. The easy answer is Sort::Naturally and use nsort.
However - sort takes a function (it defaults to cmp) that returns -1, 0, 1 depending on relative position.
So sorting 'by IP' might look like this:
sub by_ip {
my #a = split /\./, $a;
my #b = split /\./, $b;
foreach my $octet ( #a ) {
my $comparison = $octet <=> shift ( #b );
return $comparison if $comparison;
}
return 0;
}
And then you could:
foreach my $ip ( sort by_ip keys %ports_from ) {
print "$ip: ", join ( " ", sort { $a <=> $b } #{$ports_from{$ip}}),"\n";
}
Giving you:
24.64.208.134 : 24128 24128 24128
71.228.199.109 : 37091
72.197.8.56 : 9258
75.117.31.43 : 3122
99.248.20.48 : 48725
207.68.178.56 : 80
Given an IP-to-port mapping where duplicates exist though, it might be better still to merely count port-frequency using a hash-of-hashes instead of a hash-of-arrays.
$count_ports_from{$source}{$src_port}++;
And then:
foreach my $ip ( sort by_ip keys %count_ports_from ) {
print "$ip: ";
foreach my $port_num ( sort { $count_ports_from{$a} <=> $count_ports_from{$b} }
keys %{ $count_ports_from{$ip} } )
{
print "\t $port_num : $count_ports_from{$ip}{$port_num}\n";
}
}
Giving you something like:
24.64.208.134 : 24128 : 3
71.228.199.109 : 37091 : 1
72.197.8.56 : 9258 : 1
75.117.31.43 : 3122 : 1
99.248.20.48 : 48725 : 1
207.68.178.56 : 80 : 1
How can I print and get index from regex here:
my $search1 = "aaaNAMEaaaa";
my $search2 = "bbbbCHECKbbb";
if ( $search1 =~ /na\we/i and $search2 =~ /che\wk/i ) {
print "String found\n";
# This works with one search
# my $matched = $&;
# my $pos = index( $search1, $matched );
}
If both expressions match, $& will only have the last match. i.e. for the example above $& will always have the value CHECK and never have NAME because it was overwritten by the second pattern match.
You can wrap this logic in a function, then call that function as many times as you'd like with different string, pattern combinations:
use strict;
use warnings;
my $search1 = "aaaNAMEaaaa";
my $search2 = "bbbbCHECKbbb";
print index_from_match($search1, qr/na\we/i), "\n"; # 3
print index_from_match($search2, qr/che\wk/i), "\n"; # 4
print index_from_match($search1, qr/che\wk/i), "\n"; # -1
sub index_from_match {
my ($s, $pattern) = #_;
# uses a capture group instead of $&
if ( my ($match) = $s =~ m/($pattern)/ ) {
return index($s, $match);
}
return -1;
}
The core problem is that you're doing two regex comparisons in a single expression, so the values for the first one are lost before they can be processed
It's really hard to see how to help you without understanding the program flow within the conditional statement and how you actually use those values
Other languages use the idea of a match object, and it's easy to simulate that here by writing a subroutine that returns either a [ string, offset ] pair if the pattern matched, or undef if not. It's also less wasteful to use the built-in #- and #+ arrays to provide the values needed instead of repeating the search with index
It would look like this
use strict;
use warnings 'all';
use Carp 'croak';
my $search1 = 'aaaNAMEaaaa';
my $search2 = 'bbbbCHECKbbb';
my $match1 = match($search1, /na\we/i);
my $match2 = match($search2, qr/che\wk/i);
if ( $match1 and $match2 ) {
print "String found\n";
printf qq{"%s" found at offset %d\n}, #$match1;
printf qq{"%s" found at offset %d\n}, #$match2;
}
sub match {
my ($s, $re) = #_;
croak "Compiled regex required" unless ref $re eq 'Regexp';
return unless $s =~ $re;
[ substr($s, $-[0], $+[0]-$-[0]), $-[0] ];
}
output
String found
"NAME" found at offset 3
"CHECK" found at offset 4
I think it would also be neater to write this as
my $match1 = match($search1, qr/na\we/i);
my $match2 = match($search2, qr/che\wk/i);
if ( $match1 and $match2 ) {
print "String found\n";
printf qq{"%s" found at offset %d\n}, #$match1;
printf qq{"%s" found at offset %d\n}, #$match2;
}
Break your compound if into multiple if statements
my $search1 = "aaaNAMEaaaa";
my $search2 = "bbbbCHECKbbb";
my ($matched1, $matched2, $pos1, $pos2);
if ( $search1 =~ /na\we/i) {
$matched1 = $&;
$pos1 = index( $search1, $matched1);
if ($search2 =~ /che\wk/i ) {
print "String found\n";
$matched2 = $&;
$pos2 = index( $search2, $matched2);
#do whatever you need with $pos1 & $pos2
} else {
#reset previously set vars
undef $matched1;
undef $pos1;
}
}
My script loads some stuff from some files in some arrays, you enter a text from the keyboard, the script searches the relevant part of the text in those arrays, if it finds it, it does something, if not, well, another thing, at least in theory.
I get the following errors:
Use of uninitialized value in pattern match (m//) at emo_full_dynamic.pl line 120, <STDIN> chunk 2.
Modification of a read-only value attempted at emo_full_dynamic.pl line 121, <STDIN> chunk 2.
line 120 = $plm3 =~ /arr_(\w+.txt)/;
My problem, I think, is at $plm3 =~ /arr_(\w+.txt)/;. I used it so that I can store the name of an array in $1.
Here's my code:
#!/usr/bin/perl
use warnings;
$idx = 0;
$oldsep = $/;
opendir(DIR, 'c:/downloads/text_files/arrs/');
#files = readdir(DIR);
while ($idx <= $#files )
{
$value = $files[$idx];
if ( $value !~ m/^arr/i)
{
splice #files, $idx, 1;
}
else
{
$idx++;
}
}
foreach $plm (#files)
{
if($plm =~ m/txt$/)
{
open(ARR, "C:/downloads/text_files/arrs/$plm") or die $!;
while(<ARR>)
{ {
chomp($_);
$plm =~ m/arr_(\w+).txt/;
push(#{$1}, $_);
}
close ARR;
}
}
$plm = 0;
$idx = 0;
$stare = <STDIN>;
chomp($stare);
while($stare)
{
foreach $plm2 (#files)
{
if($plm2 =~ m/txt$/)
{
$plm2 =~ m/arr_(\w+).txt/;
if(grep $stare =~ m/$_/i, #{$1})
{
$flag = 1;
}
else
{
$flag = 0;
}
}
}
if($flag == 1)
{
$/ = "%\n";
$plm3 =~ /arr_(\w+.txt)/;
open SUPARARE, "C:/downloads/text_files/replies/$1" or die $!;
etc etc....
First of all, it's always a good idea to use strict pragma -- unless you have a valid reason to avoid it --.
Second, I don't see $plm3 initialized anywhere in your code. You have probably forgot to initialize it.
I think you are assigning something to variable $1 on line 121
Apparently there are some copy/paste issues which negates my initial answer.
Other mistakes, great and small:
You don't use strict. (fatal flaw)
Your opendir is used once, then never closed.
You use global filehandles, instead of lexical (e.g. open my $fh, ...)
Using a complext loop + splice instead of grep (#files=grep /^arr/i, #files)
Using chomp($_) when chomp per default chomps the $_ variable
I don't even know what this line means:
if(grep $stare =~ m/$_/i, #{$1}) {
You seem to be using a pattern match, where $_ is the pattern (which in this case is.. what? Nothing? Anything?), whose return value is used as a grep pattern for an array reference, that may or may not be initialized. A very horrible statement. If it indeed works as intended, the readability is very low.
Redeclaring $/ seems like a frivolous thing to do in this context, but I can't really tell, as the script ends there.