Reputation: 81
I have a program where I am trying to anchor the beginning of lines with a pipe (|). However, when I execute it, it reduces or deletes lines in my file. As you will see, I am not trying to replace anything, just put | at the beginning of certain lines. Here is the program:
$DESCRIPTION = qr/^[0-9]+\.[0-9]+ +.*? {2,}[0-9]+.*? {2,}[0-9]+.*? {2,}[0-9]+.*? {2,}[0-9]+.*?$/;
$PRICELINE = qr/^[0-9]+.*? {2,}[0-9]+.*?$/;
$PRICELINE2 = qr/^.*? {2,}[0-9]+\.[0-9]+ {2,}[0-9]+\$/;
$CODE = qr/^\w{9}$/;
$date = qr/^AS OF.*?$/;
$accountnumber = qr/^ACCOUNT NUMBER.*?$/;
$name = qr/^CEOTID.*?$/;
while (<>) {
if (s/($DESCRIPTION)/\|$1/gi) {print STDOUT "1\n"; next LINE;};
if (s/($PRICELINE)/\|$1/gi) {print STDOUT "2\n"; next LINE;};
if (s/($PRICELINE2)/\|$1/gi) {print STDOUT "3\n"; next LINE;};
if (s/($CUSIP)/\|$1/gi) {print STDOUT "4\n"; next LINE;};
if (s/($date)/\|$1/g) {print STDOUT "5\n"; next LINE;};
if (s/($accountnumber)/\|$1/gi) {print STDOUT "6\n"; next LINE;};
if (s/($name)/\|$1/gi) {print STDOUT "7\n"; next LINE;};
print;
}
print "\n\ndone"
I have tried to eliminate variables one at a time to see which one is causing the malfunction, but still no luck. I also just used a while statement but it is way slow and still deletes the first line of my file.
Any help would be great.
Upvotes: 0
Views: 118
Reputation: 118595
LINE: while (<>) {
if (s/($DESCRIPTION)/\|$1/gi) {print STDOUT "1\n"; next LINE;};
...
print;
}
When a next LINE
statement gets executed, execution goes back to the top of the loop. Your final print
statement never gets executed and it seems that some lines are "deleted".
Perl provides the while(EXPR) { BLOCK } continue { BLOCK }
syntax so that you can execute some arbitrary code at the end of an iteration. You could put your print
statement in the continue
block:
LINE: while (<>) {
if (s/($DESCRIPTION)/\|$1/gi) {print STDOUT "1\n"; next LINE;};
if (s/($PRICELINE)/\|$1/gi) {print STDOUT "2\n"; next LINE;};
if (s/($PRICELINE2)/\|$1/gi) {print STDOUT "3\n"; next LINE;};
if (s/($CUSIP)/\|$1/gi) {print STDOUT "4\n"; next LINE;};
if (s/($date)/\|$1/g) {print STDOUT "5\n"; next LINE;};
if (s/($accountnumber)/\|$1/gi) {print STDOUT "6\n"; next LINE;};
if (s/($name)/\|$1/gi) {print STDOUT "7\n"; next LINE;};
} continue {
print;
}
Now your print
statement always gets executed even if one of the if
clauses is executed.
Upvotes: 1
Reputation: 67900
EDIT: Note that you have an undeclared variable $CUSIP
which you seem to have confused with $CODE
. Without strict
and warnings
turned on, this error will be silent and deadly, but hardly discreet, as it will insert pipe symbols all over your input.
I will take a wild guess and say that it is because you are trying to use a label you have not defined: LINE
. This label is used in the following fashion:
LINE: while (<>) {
... next LINE;
}
But you can just as easily skip it and just say next
, which will refer to the innermost loop. When you do NOT have a label, however, what seems to happen in my tests is simply that it exits the loop with the error
Label not found for "next LINE" at ...
This error is shown even if warnings
is off. Which it never should be. The first two lines of any script you write should be:
use strict;
use warnings;
Because it will make your life much easier.
You should also know that you can use lookahead assertions to solve what you are trying to do:
if (s/(?=$DESCRIPTION)/|/i) { ... }
You should be aware that this:
print STDOUT "1\n";
..still prints to the file if you are using inplace edit via the -p
and -i
switch. If you want some kind of feedback, you can print to STDERR:
print STDERR "1\n";
warn "1\n"; # same thing
Also, you don't have to use the s///
operator at all, you can just check the line, and then use string interpolation to add a pipe symbol:
if (/$DESCRIPTION/) { $_ = "|$_" }
Also, you don't have to use next
at all: You can use plain old fashioned logic:
if (/$DESCRIPTION/) { ... }
elsif (/$PRICELINE/) { ... }
So there you have it. And please, start using strict
and warnings
.
Upvotes: 4