perl if line matches regex, ignore line and move onto next line in file - perl

How would you do the following in perl:
for $line (#lines) {
if ($line =~ m/ImportantLineNotToBeChanged/){
#break out of the for loop, move onto the next line of the file being processed
#start the loop again
}
if ($line =~ s/SUMMER/WINTER/g){
print ".";
}
}
Updated to show more code, this is what I'm trying to do:
sub ChangeSeason(){
if (-f and /.log?/) {
$file = $_;
open FILE, $file;
#lines = <FILE>;
close FILE;
for $line (#lines) {
if ($line =~ m/'?Don't touch this line'?/) {
last;
}
if ($line =~ m/'?Or this line'?/){
last;
}
if ($line =~ m/'?Or this line too'?/){
last;
}
if ($line +~ m/'?Or this line as well'?/){
last;
}
if ($line =~ s/(WINTER)/{$1 eq 'winter' ? 'summer' : 'SUMMER'}/gie){
print ".";
}
}
print "\nSeason changed in file $_";
open FILE, ">$file";
print FILE #lines;
close FILE;
}
}

Just use next
for my $line (#lines) {
next if ($line =~ m/ImportantLineNotToBeChanged/);
if ($line =~ s/SUMMER/WINTER/g){
print ".";
}
}

for $line (#lines) {
unless ($line =~ m/ImportantLineNotToBeChanged/) {
if ($line =~ s/SUMMER/WINTER/g){
print ".";
}
}
}
A more concise method is
map { print "." if s/SUMMER/WINTER/g }
grep {!/ImportantLineNotToBeChanged/} #lines;
(I think I got that right.)

Just use the next feature.
for $line (#lines) {
if ($line =~ m/ImportantLineNotToBeChanged/){
#break out of the for loop, move onto the next line of the file being processed
#start the loop again
next;
}
if ($line =~ s/SUMMER/WINTER/g){
print ".";
}
}
Similarly, you can use "last" to finish the loop. For example:
for $line (#lines) {
if ($line =~ m/ImportantLineNotToBeChanged/){
#continue onto the next iteration of the for loop.
#skip everything in the rest of this iteration.
next;
}
if ($line =~ m/NothingImportantAFTERThisLine/){
#break out of the for loop completely.
#continue to code after loop
last;
}
if ($line =~ s/SUMMER/WINTER/g){
print ".";
}
}
#code after loop
Edit: 7pm on 6/13
I took your code and looked at it, rewrote some things and this is what I got:
sub changeSeason2 {
my $file= $_[0];
open (FILE,"<$file");
#lines = <FILE>;
close FILE;
foreach $line (#lines) {
if ($line =~ m/'?Don't touch this line'?/) {
next;
}
if ($line =~ m/'?Or this line'?/){
next;
}
if ($line =~ m/'?Or this line too'?/){
next;
}
if ($line =~ m/\'Or this line as well\'/){
next;
}
if ($line =~ s/(WINTER)/{$1 eq 'winter' ? 'summer' : 'SUMMER'}/gie){
print ".";
}
}
print "\nSeason changed in file $file";
open FILE, ">$file";
print FILE #lines;
close FILE;
}
Hope this helps some.

Unless I'm misunderstanding you, your "break out of the for loop, move onto the next line... [and] start the loop again" is just a complex way of saying "skip the loop body for this iteration".
for $line (#lines) {
unless (($line =~ m/ImportantLineNotToBeChanged/) {
if ($line =~ s/SUMMER/WINTER/g) {
print ".";
}
}
}

Related

Doubts group data

I need a help with the following problem. I have a file with the following data.
21997|||70049,,20170428154818,20170527235959|||
21997|||70070,,20170428154739,20170527235959|||
21998|||70049,,20170428154818,20170527235959|||
21998|||70070,,20170428154739,20170527235959|||
21998|||70071,,20170428154739,20170527235959|||
I need to unify the file as follows.
21997|||70049,,20170502172844,20170531235959; 70070,,20170502172844,20170531235959|||
21998|||70049,,20170502172844,20170531235959; 70070,,20170502172844,20170531235959; 70071,,20170502172844|||
Can someone help me please?
my $unified_output;
my %out;
open(FILE, "./raw-file.txt") or die $!;
my #file = <FILE>;
close FILE;
for (#file) {
next if $_ =~ /$^/;
my #line = split(/\|\|\|/, $_) if $_;
$out{"$line[0]"} .= qq~$line[1]; ~ if $_ and $_ =~ /^$line[0]/;
}
for (keys %out) {
$out{$_} =~ s!\; $!!;
$unified_output .= qq~$_|||$out{$_}|||\n~ if $_ and $out{$_};
}

Quit while-loop if statement is true

I have a subfunction and inside of it I am reading a file in Perl with the usual while-loop line-by-line because that's the only (and best?) option I know in Perl so far. Now I am searching line-based for a keyword with a loop like
my $var;
open(FILE, "stuff.dat")
while (my $line = <FILE>){
if ($line =~ /regex/) {
$var = $1;
return $var;
} else {
return "var is not defined!";
}
}
close(FILE);
but even when it gets the keyword and $var is specified, it gets overwritten on the next line. So I want to quit the while-loop if the keyword is found and $var is defined.
I tried next if or next unless or the last-exit but this isn't working properly and perldoc states that we can't use last for subs.
open(my $FILE, "<", "stuff.dat") or die $!;
while (my $line = <$FILE>){
if ($line =~ /regex/) {
return $1 if defined $1;
}
}
close($FILE);
return "var is not defined!";
open(FILE, "stuff.dat")
my $var;
while (my $line = <FILE>){
if ($line =~ /regex/) {
$var = $1;
last;
}
}
close(FILE);
return $var;
Hope this helps.
You can add the regexp evaluation to the while loop condition, without using return or last.
sub check_file {
open(FILE, "stuff.dat") or die;
my $result;
my $line;
while (($line = <FILE>) && ($result = ($line !~ m/regex/))) {};
close(FILE);
## $result equals 1 only if we have exit the loop and
## didn't have a match till the last line of the file
return ($result != 1);
}

Why I am not getting "success" with this program?

I have written the following program with the hope of getting success. But I could never get it.
my $fileName = 'myfile.txt';
print $fileName,"\n";
if (open MYFILE, "<", $fileName) {
my $Data;
{
local $/ = undef;
$Data = <MYFILE>;
}
my #values = split('\n', $Data);
chomp(#values);
if($values[2] eq '9999999999') {
print "Success"."\n";
}
}
The content of myfile.txt is
160002
something
9999999999
700021
Try splitting by \s*[\r\n]+
my $fileName = 'myfile.txt';
print $fileName,"\n";
if (open MYFILE, "<", $fileName) {
my $Data;
{
local $/ = undef;
$Data = <MYFILE>;
}
my #values = split(/\s*[\r\n]+/, $Data);
if($values[2] eq '9999999999') {
print "Success";
}
}
If myfile.txt contain carriage return (CR, \r), it will not work as expected.
Another possible cause is trailing spaces before linefeed (LF, \n).
You don't need to read an entire file into an array to check one line. Open the file, skip the lines you don't care about, then play with the line you do care about. When you've done what you need to do, stop reading the file. This way, only one line is ever in memory:
my $fileName = 'myfile.txt';
open MYFILE, "<", $fileName or die "$filename: $!";
while( <MYFILE> ) {
next if $. < 3; # $. is the line number
last if $. > 3;
chomp;
print "Success\n" if $_ eq '9999999999';
}
close MYFILE;
my $fileName = 'myfile.txt';
open MYFILE, "<", $fileName || die "$fileName: $!";
while( $rec = <MYFILE> ) {
for ($rec) { chomp; s/\r//; s/^\s+//; s/\s+$//; } #Remove line-feed and space characters
$cnt++;
if ( $rec =~ /^9+$/ ) { print "Success\n"; last; } #if record matches "9"s only
#print "Success" and live the loop
}
close MYFILE;
#Or you can write: if ($cnt==3 and $rec =~ /^9{10}$/) { print "Success\n"; last; }
#If record 3 matches ten "9"s print "Success" and live the loop.

Store value (strings or numbers) into an array after performing while loop

I have a while loop below:
while (<>)
{
my $line = $_;
if ($line =~ m/ERROR 0x/)
{
$error_found +=1;
}
}
After while loop finished, i will match somethings like "ERROR..." and i wanna store them into an array or list or hash. How can i do this?
Just push the data into an array.
my #errors;
while (<>)
{
my $line = $_;
if ($line =~ m/ERROR 0x/)
{
push #errors, $line;
}
}
Clean things up a little:
my #errors;
while (my $line = <>)
{
if ($line =~ /ERROR 0x/)
{
push #errors, $line;
}
}
Or maybe even
my #errors;
while (<>)
{
if (/ERROR 0x/)
{
push #errors, $_;
}
}
Finally, realize that grep would do great here:
my #errors = grep { /ERROR 0x/ } <>;
my #arr;
while (<>)
{
my $line = $_;
if ($line =~ m/ERROR 0x/)
{
push(#arr,$line) ;
}
}
print "$_\n" for #arr;

How to match 2 patterns within a single line

I have the following Java code
fun(GUIBundle.getString("Key1"), GUIBundle.getString("Key2"));
I use Perl to parse the source code, to see whether "Key1" and "Key2" is found within $gui_bundle.
while (my $line = <FILE>) {
$line_number++;
if ($line =~ /^#/) {
next;
}
chomp $line;
if ($line =~ /GUIBundle\.getString\("([^"]+)"\)/) {
my $key = $1;
if (not $gui_bundle{$key}) {
print "WARNING : key '$key' not found ($name $line_number)\n";
}
}
}
However, for the way I write the code, I can only verify "Key1". How I can verify "Key2" as well?
Add the g modifier and put it into a while loop:
while ($line =~ /GUIBundle\.getString\("([^"]+)"\)/g) { ...
Just use the /g modifier to the regular expression match, in list context:
#matches = $line =~ /GUIBundle\.getString\("([^"]+)"\)/g;
Given your example line, #matches will contain strings: 'Key1' and 'Key2'.
Exchange the if construct with a while, and using the global-matching modifier, /g:
while (my $line = <FILE>) {
$line_number++;
next if $line =~ /^#/;
chomp $line;
while ($line =~ /GUIBundle\.getString\("([^"]+)"\)/g) { #"
my $key = $1;
warn "key '$key' not found ($name $line_number)" unless $gui_bundle{$key};
}
}