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
Related
I am trying to read a log file and write all the error logs to a new file. I must also keep track of how many errors there are and the number of messages in general. I must assume that the logs will be broken up onto multiple lines, so I have been using regex and series a variables to search for all possibilities and write to the appropriate file.
My file handles are: FILE, ERRORFILE, and SUCCESSFILE.
use strict;
use warnings;
my $totalcount = 0;
my $errorcount = 0;
my $log = "s"; # $log controls what what should be written where,
# incase it doesn't start with code.
# "s" = SuccessFile, "e" = ErrorFile
my $logStart = "y"; # used with m/^I/ or m/^E/ instead of full code
# incase the code is broken into pieces.
my $dash = 0;
while (<FILE>) {
$dash += () = $_ =~ m/-/g; # can't use tr/// because it counts at compile
if ( $dash lt 25 ) { next; } # this line skips "---Begin <Repository>---"
elsif ( m/[a-zA-Z <>]/ && $dash lt 25 ) { next; }
elsif ( $dash >= 26 ) { last; } #Ends loop at "---End <Repository>---"
if ( m/^I/ && $logStart eq "y" ) {
$log = "s";
$logStart = "n";
$totalcount++;
next;
} #Ignores nonerror logs
elsif ( m/^E/ && $logStart eq "y" ) {
chomp $_;
print ERRORFILE "$_";
$errorcount++;
$totalcount++;
$log = "e";
$logStart = "n";
}
elsif (m/ \.\n$/) { #End of log
if ( $log eq "s" ) { $logStart = "y"; next; }
print ERRORFILE "$_\n" if $log eq "e";
$logStart = "y";
}
else { #line doesn't start with code or end in " .\n"
chomp $_;
print ERRORFILE "$_" if $log eq "e";
next if $log eq "s";
}
}
print "\nThere are $errorcount error logs.\n";
print "There are $totalcount logs in the full log file.\n";
I know that the non-error logs start with I00020036 and the errors start with E03020039. Both end in " .\n"
---------- Begin <Load Repository> ---------------
I00020036: Loaded C:\Documents and Settings\dorja03\Desktop\DSMProduct\external\etpki\Linux_2.4_x86\redistrib\readme.txt into \DSM R11\external\etpki\Linux_2.4_x86\redistrib\readme.txt .
E03020039: Unable to load C:\Documents and Settings\dorja03\Desktop\DSMProduct\external\etpki\Linux_2.4_x86\redistrib\etpki_install_lib.sh into \DSM R11\external\etpki\Linux_2.4_x86\redistrib\etpki_install_lib.sh . Text file contains invalid characters .
---------- End <Load Repository> ---------------
I have been running a test sample with two lines. If the error comes up first, it will print it to the error file, along with the non-error log, and on the same line. If the non-error goes first, it doesn't recognize the error.
Is this because I'm using m// wrong or something else entirely?
Edit: Test input has been added. I also added the code to skip the header and footer.
Test output: If the non-error comes first, there are 0 errors and 1 log total.
If the non-error comes first, there is 1 error and 1 log total.
If this worked, it should have said there was 1 error and 2 logs. It also would have only printed the error to the ERRORFILE.
This won't answer why your code isn't working, but here's how I would approach the problem:
Since the logs can span over multiple lines, modify the default line-by-line behavior by tweaking $/.
Use appropriate data structures to filter the errors from non-errors. This will also allow you to defer printing till later.
The code would then look something like this:
use strict;
use warnings;
my %logs;
local $/ = " .\n";
while ( <> ) { # Now $_ is the full (multi-line) log
next if /--- Begin/; # Skip if /Begin/
last if /--- End/; # Stop processing if /End/
if ( m/^I/ ) {
push #{ $logs{nonerror} }, $_;
}
if ( m/^E/ ) {
push #{ $logs{error} }, $_;
}
}
printf "There are %d error logs\n.", scalar #{ $logs{error} // [] } ;
printf "There are %d logs in the full logfile.\n",
#{$logs{error} // []} + #{$logs{nonerror} // []};
Things I like about this approach:
Perl takes care of deciding when each log message ends (eliminates the $logStart variable altogether).
The logic is much easier to extend.
The while loop is dedicated to processing the log file (no need to ++ anything).
Use of sensibly-labeled data structures instead of temporary variables makes for easier code maintenance.
To make a formal answer, I scrapped this code and replaced it. I instead fed the file into var with a delimiter, then just split it into an array. It was much easier and cleaner. I don't however have the code anymore due to a lost flashdrive.
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';
How can I find the number of times a word is in a block of text in Perl?
For example my text file is this:
#! /usr/bin/perl -w
# The 'terrible' program - a poorly formatted 'oddeven'.
use constant HOWMANY => 4; $count = 0;
while ( $count < HOWMANY ) {
$count++;
if ( $count == 1 ) {
print "odd\n";
} elsif ( $count == 2 ) {
print "even\n";
} elsif ( $count == 3 ) {
print "odd\n";
} else { # at this point $count is four.
print "even\n";
}
}
I want to find the number of "count" word for that text file. File is named terrible.pl
Idealy it should use regex and with minimum number of line of code.
EDIT: This is what I have tried:
use IO::File;
my $fh = IO::File->new('terrible.pl', 'r') or die "$!\n";
my %words;
while (<$fh>) {
for my $word ($text =~ /count/g) {
print "x";
$words{$word}++;
}
}
print $words{$word};
Here's a complete solution. If this is homework, you learn more by explaining this to your teacher than by rolling your own:
perl -0777ne "print+(##=/count/g)+0" terrible.pl
If you are trying to count how many times appears the word "count", this will work:
my $count=0;
open(INPUT,"<terrible.pl");
while (<INPUT>) {
$count++ while ($_ =~ /count/g);
}
close(INPUT);
print "$count times\n";
I'm not actually sure what your example code is but you're almost there:
perl -e '$text = "lol wut foo wut bar wut"; $count = 0; $count++ while $text =~ /wut/g; print "$count\n";'
You can use the /g modifier to continue searching the string for matches. In the example above, it will return all instances of the word 'wut' in the $text var.
You can probably use something like so:
my $fh = IO::File->new('test.txt', 'r') or die "$!\n";
my %words;
while (<$fh>) {
for my $word (split / /) {
$words{$word}++;
}
}
That will give you an accurate count of every "word" (defined as a group of characters separated by a space), and store it in a hash which is keyed by the word with a value of the number of the word which was seen.
perdoc perlrequick has an answer. The term you want in that document is "scalar context".
Given that this appears to be a homework question, I'll point you at the documentation instead.
So, what are you trying to do? You want the number of times something appears in a block of text. You can use the Perl grep function. That will go through a block of text without needing to loop.
If you want an odd/even return value, you can use the modulo arithmetic function. You can do something like this:
if ($number % 2) {
print "$number is odd\n"; #Returns a "1" or true
}
else {
print "$number is even\n"; #Returns a "0" or false
}
I would like to convert parse (la)tex math expressions, and convert them to (any kind of!) scripting language expression, so I can evaluate expressions.
What libraries do you recommend ?
May be it will help - take a look at TeXmacs, especially at a way it interacts with computer algebra systems.
Here is a set of possible options from a similar question. https://tex.stackexchange.com/questions/4223/what-parsers-for-latex-mathematics-exist-outside-of-the-tex-engines
I think that Perl would make a fine choice for something like this, acting on text is one of its fortes.
Here is some info on how to make an exclusive flip-flop test (to find the context between \begin{} and \end{} without keeping those lines), http://www.effectiveperlprogramming.com/2010/11/make-exclusive-flip-flop-operators/
EDIT: So this problem has started me going. Here is a first attempt to create something here is my "math.pl" which takes a .tex file as an arguement (i.e. $./math.pl test.tex).
#!/usr/bin/env perl
use strict;
use warnings;
use Text::Balanced qw/extract_multiple extract_bracketed/;
my $re_num = qr/[+\-\dE\.]/;
my $file = shift;
open( my $fh, '<', $file);
#parsing this out for more than just the equation environment might be easier using Text::Balanced too.
my #equations;
my $current_equation = '';
while(<$fh>) {
my $test;
next unless ($test = /\\begin\{equation\}/ .. /\\end\{equation\}/);
if ($test !~ /(^1|E0)$/ ) {
chomp;
$current_equation .= $_;
} elsif ($test =~ /E0$/) {
#print $current_equation . "\n";
push #equations, {eq => $current_equation};
$current_equation = '';
}
}
foreach my $eq (#equations) {
print "Full Equation: " . $eq->{'eq'} . "\n";
solve($eq);
print "Result: " . $eq->{'value'} . "\n\n";
}
sub solve {
my $eq = shift;
print $eq->{'eq'} . "\n";
parse($eq);
compute($eq);
print "intermediate result: " . $eq->{'value'} . "\n";
}
sub parse {
my $eq = shift;
my ($command,#fields) = extract_multiple(
$eq->{'eq'}, [ sub { extract_bracketed(shift,'{}') } ]
);
$command =~ s/^\\//;
print "command: " . $command . "\n";
#fields = map { s/^\{\ *//; s/\ *\}$//; print "arg: $_\n"; {value => $_}; } #fields;
($eq->{'command'}, #{ $eq->{'args'} }) = ($command, #fields);
}
sub compute {
my ($eq) = #_;
#check arguements ...
foreach my $arg (#{$eq->{'args'}}) {
#if arguement is a number, continue
if ($arg->{'value'} =~ /^$re_num$/) {
next;
#if the arguement is a simple mathematical operation, do it and continue
} elsif ($arg->{'value'} =~ /^($re_num)\ *(?:\ |\*|\\times)?\ *($re_num)$/) {
$arg->{'value'} = $1 * $2;
} elsif ($arg->{'value'} =~ /^($re_num)\ *(?:\+)?\ *($re_num)$/) {
$arg->{'value'} = $1 + $2;
} elsif ($arg->{'value'} =~ /^($re_num)\ *(?:\-)?\ *($re_num)$/) {
$arg->{'value'} = $1 - $2;
} elsif ($arg->{'value'} =~ /^($re_num)\ *(?:\/)?\ *($re_num)$/) {
$arg->{'value'} = $1 / $2;
} else {
#parse it and calc it as if it were its own equation.
$arg->{'eq'} = $arg->{'value'};
solve($arg);
}
}
my #args = #{$eq->{'args'}};
## add command processing here
# frac
if ($eq->{'command'} eq 'frac') {
$eq->{'value'} = $args[0]->{'value'} / $args[1]->{'value'};
return;
}
}
and here is a sample test.tex:
\documentclass{article}
\begin{document}
Hello World!
\begin{equation}
\frac{\frac{1}{3}}{2}
\end{equation}
\end{document}
Maybe using boost::spirit in order to tokenize the expression. You will need to define a huge grammar!
Use a parser generator to create an appropriate parser. Try ANTLR for this, as it includes an IDE for the Grammar, which is very helpful. Using tree rewrite rules, you can then convert the parse tree to an abstract syntax tree.
Start perhaps with the expression evaluator from ANTLR tutorial. I think this is reasonably close enough.
I'm trying to make an on-the-fly pattern tester in Perl.
Basically it asks you to enter the pattern, and then gives you a >>>> prompt where you enter possible matches. If it matches it says "%%%% before matched part after match" and if not it says "%%%! string that didn't match". It's trivial to do like this:
while(<>){
chomp;
if(/$pattern/){
...
} else {
...
}
}
but I want to be able to enter the pattern like /sometext/i rather than just sometext
I think I'd use an eval block for this? How would I do such a thing?
This sounds like a job for string eval, just remember not to eval untrusted strings.
#!/usr/bin/perl
use strict;
use warnings;
my $regex = <>;
$regex = eval "qr$regex" or die $#;
while (<>) {
print /$regex/ ? "matched" : "didn't match", "\n";
}
Here is an example run:
perl x.pl
/foo/i
foo
matched
Foo
matched
bar
didn't match
^C
You can write /(?i:<pattern>)/ instead of /<pattern>/i.
This works for me:
my $foo = "My bonnie lies over the ocean";
print "Enter a pattern:\n";
while (<STDIN>) {
my $pattern = $_;
if (not ($pattern =~ /^\/.*\/[a-z]?$/)) {
print "Invalid pattern\n";
} else {
my $x = eval "if (\$foo =~ $pattern) { return 1; } else { return 0; }";
if ($x == 1) {
print "Pattern match\n";
} else {
print "Not a pattern match\n";
}
}
print "Enter a pattern:\n"
}