How to match an integer after finding a keyword? - perl

I have a text file content as below:
Starting log...
Sample at 10000000
Mode is set to 0
0007F43: CHANGE DETECTED at 290313 line 0 from 00 to 04
0007F46: Mismatched at 290316 line 0
0007F50: Matched occur at 290326 line 1
0007F53: Mismatched at 290336 line 2
0007F56: Matched occur at 290346 line 0
0007F60: Mismatched at 290356 line 2
0007F63: Matched occur at 290366 line 0
Saving log....
DONE!!!
I am running simple perl program as below to get the value for the line contains "Mismatched"
#!/usr/bin/perl
print "Starting perl script\n\n";
open (LOG,"dump.log");
while (<LOG>) {
next if !/Mismatched/;
/at\s+"([^"]+)"/;
print $1,"\n";
}
close(LOG);
print "DONE!!\n";
exit;
but what i get the error message as below, may I know what's wrong with my coding? Is it I miss anything related with chomp()?
Use of uninitialized value in print at test.pl line 9, <LOG> line 5.
Use of uninitialized value in print at test.pl line 9, <LOG> line 7.
Use of uninitialized value in print at test.pl line 9, <LOG> line 9.
DONE!!
And.. is there any suggestion to get the integer (i.e. 290316) after searching the keyword "Mismatched" by using more simple scripting? I just want to get the first value only..

$1 is getting printed even if it does not have anything. It should be in a condition:
print $1,"\n" if (/Mismatched at (\d+)/);
To store all values in an array:
push #arr,$1 if (/Mismatched at (\d+)/);

change regex to:
/at\s+(\d+)/;

You've got answers that show you the correct way to do this, but nothing yet that explains what you were doing wrong. The problem is in your regex.
/at\s+"([^"]+)"/
Let's break it down and see what it's trying to match.
at : the string 'at'
\s+ : one or more whitespace characters
" : a double quote character
([^"]+) : one or more characters that aren't double quote characters
" : a double quote character
So, effectively, you're looking for 'at' followed by a double quoted string. And you're capturing (into $1) the contents of the double quoted string.
But none of your data contains any double quote characters. So there are no double quoted strings. So nothing ever matches and nothing ever gets captured into $1. Which is why you get the 'uninitialised value' error when you try to print $1.
I'd be interested to hear why you thought you wanted to match double quote characters in a piece of text that doesn't contain any of them.

I'd change your script to implement a more modern perl style:
#!/usr/bin/perl
use strict;
use warnings;
print "Starting perl script\n\n";
open my $LOG, '<', 'dump.log' or die $!;
while( <$LOG> ) {
print "$1\n" if /Mismatched at (\d+)/;
}
close $LOG;
print "DONE!!\n";

Related

Unable to read the input file content that containing % sign

I am having simple open file input as showing below, which I have no problem reading the content from the input file, but not entirely readable.
open(IN,"<$modelRoot/Local_$project.pm") || die "ERROR\: $!";
while(<IN>)
{
$temp = $_;
chomp($temp);
printf "$temp\n";
}
The content that I printed out looks fine until the point that is a % sign.
This is the original input file content
my %LocalToolData = (
This is the content that I print out, it gives a warning too
Use of uninitialized value in printf at rfinteg_v4.pl line 846, <IN> line 24.
Use of uninitialized value in printf at rfinteg_v4.pl line 847, <IN> line 24.
my 0calToolData = (
Question: How do I read % sign from the input file and at the same time avoid having the warning?
printf does formatting using %, it's a reserved character. The first argument to printf is a template string, not any string.
You should be using print unless you want to make use of that feature.
You should not use printf with any content containing % unless you have corresponding placeholder values for that.
It even says in the documentation:
Don't fall into the trap of using a printf when a simple print would do. The print is more efficient and less error prone.

How do I select text between two specific symbols in Perl?

I'm very new to Perl. I'm currently going through this Perl file and I've got this variable where I was able to format it down to get all the text after the "<" symbol using this line I found from another stackflow question.
($tempVariable) = $Line =~ /(\<.*)\s*$/;
So currently whenever I print this variable, I get the output
$tempVariable = <some text here #typeOf and more text here after
I need to get everything between the "<" symbol and the "#"symbol.
I tried looking at other stackflow questions and tried implementing it to mines but I keep getting errors so if anybody could help me out I would appreciate it.
my ($substr) = $str =~ /<([^<\#]*)\#/
or die "No match";
You'll need a regex that
looks for the starting < character
then (your question is unclear on this point)
captures one-or-more non-# characters, or
captures zero-or-more non-# characters
looks for the trailing # character
also not specified in your question: do you need to strip leading and trailing white space from the match?
I.e.
#!/usr/bin/perl
use warnings;
use strict;
my $Line = '<some text here #typeOf and more text here after';
my $tempVariable;
# alternative 1: one-or-more characters
($tempVariable) = $Line =~ /<([^#]+)#/
or die "No match alternative 1";
print "Alternative 1: '${tempVariable}'\n";
# alternative 2: zero-or-more characters
($tempVariable) = $Line =~ /<([^#]*)#/
or die "No match alternative 2";
print "Alternative 2: '${tempVariable}'\n";
exit 0;
Test run (white space is not stripped):
$ perl dummy.pl
Alternative 1: 'some text here '
Alternative 2: 'some text here '

Perl chomp doesn't remove the newline

I want to read a string from a the first line in a file, then repeat it n repetitions in the console, where n is specified as the second line in the file.
Simple I think?
#!/usr/bin/perl
open(INPUT, "input.txt");
chomp($text = <INPUT>);
chomp($repetitions = <INPUT>);
print $text x $repetitions;
Where input.txt is as follows
Hello
3
I expected the output to be
HelloHelloHello
But words are new line separated despite that chomp is used.
Hello
Hello
Hello
You may try it on the following Perl fiddle CompileOnline
The strange thing is that if the code is as follows:
#!/usr/bin/perl
open(INPUT, "input.txt");
chomp($text = <INPUT>);
print $text x 3;
It will work fine and displays
HelloHelloHello
Am I misunderstanding something, or is it a problem with the online compiler?
You have issues with line endings; chomp removes trailing char/string of $/ from $text and that can vary depending on platform. You can however choose to remove from string any trailing white space using regex,
open(my $INPUT, "<", "input.txt");
my $text = <$INPUT>;
my $repetitions = <$INPUT>;
s/\s+\z// for $text, $repetitions;
print $text x $repetitions;
I'm using an online Perl editor/compiler as mentioned in the initial post http://compileonline.com/execute_perl_online.php
The reason for your output is that string Hello\rHello\rHello\r is differently interpreted in html (\r like line break), while in console \r returns cursor to the beginning of the current line.

Use of uninitialized value in concatenation (.) or string

I have just beginner in perl and write small piece of code.After Adding \n, I am getting the below error.Please find the table format below.I am trying to fetch ( 2 and 3 column)
from temp.txt after index.I am trying to ingnore first two line.
As I mentioned,I got error when I add \n into code
Error : Use of uninitialized value in concatenation (.) or
string at temp.pl line 10, <$fh2> line 300.
#! /usr/bin/perl
use strict;
use warnings;
my #data;
open(my $fh2,'<',"temp.txt") or die "Could not open file";
while(my $line =<$fh2>){
#data =split(/\s+/,$line);
print "$data[2] $data[3]";
print "\n";
}
Table format is:
$DATA1 SOURCE='XtA' VERSION='G-2014.06'
.TITLE '%curve%'
index temp1 temp2 temp3
alter#
1 -1.5750000e+00 -3.2053667e+00 -4.0000000e+01
1.0000000e+00(temp4)
2 -1.5272727e+00 -2.9323414e+00 -4.0000000e+01
1.0000000e+00
3 -1.4795454e+00 -2.6579232e+00 -4.0000000e+01
1.0000000e+00
....................................upto 99
temp1 temp2
<val1> <val2>
After you split do:
if (scalar(#data)==4) {
THEN YOUR PRINT CODE
}
Because you don't know if $data[3] or $data[2] exists.
You need to give us the full error. You should edit the question and then cut and paste the exact error, including the line number. Then, tell us what line in the file that is.
Chances are that in some of the data in that file there are fewer than 4 fields. Therefore, the split returns 3 or fewer scalars into #data. Then, when you try to refer to $data[3], that's an uninitialized value.

Is there a one-liner to get the first element of a split?

Instead of writing:
#holder = split /\./,"hello.world";
print #holder[0];
is it possible to just do a one-liner to just get the first element of the split? Something like:
print (split /\./,"hello.world")[0]
I get the following error when I try the second example:
print (...) interpreted as function at test.pl line 3.
syntax error at test.pl line 3, near ")["
You should have tried your hunch. That’s how to do it.
my $first = (split /\./, "hello.world")[0];
You could use a list-context assignment that grabs the first field only.
my($first) = split /\./, "hello.world";
To print it, use
print +(split /\./, "hello.world")[0], "\n";
or
print ((split(/\./, "hello.world"))[0], "\n");
The plus sign is there because of a syntactic ambiguity. It signals that everything following are arguments to print. The perlfunc documentation on print explains.
Be careful not to follow the print keyword with a left parenthesis unless you want the corresponding right parenthesis to terminate the arguments to the print; put parentheses around all arguments (or interpose a +, but that doesn't look as good).
In the case above, I find the case with + much easier to write and read. YMMV.
If you insist on using split for this then you could potentially be splitting a long string into multiple fields, only to discard all but the first. The third parameter to split should be used to limit the number of fields into which to divide the string.
my $string = 'hello.world';
print((split(/\./, $string, 2))[0]);
But I believe a regular expression better describes what you want to do, and avoids this problem completely.
Either
my $string = 'hello.world';
my ($first) = $string =~ /([^.]+)/;
or
my $string = 'hello.world';
print $string =~ /([^.]+)/;
will extract the first string of non-dot characters for you.
I get the following error when I try the second example:
"syntax error at test.pl line 3, near ")["
No, if you have warnings enabled as you should, you get:
print (...) interpreted as function at test.pl line 3.
syntax error at test.pl line 3, near ")["
which should be a big clue as to your problem.