Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I need to insert a string only once after matching the comments. This should be trivial but maybe I'm too tired to think it through. :( There are a few hundred files and they contain different syntaxes for the comments. I found a similar question at this node but the solution would match multiple times. My code currently updates the first line of the file and I want it to update after all the current comments. Thanks for any tips!
open (IN, 'file.txt'); my $out = ''; my $newComment = 0; while (<IN>) { if(($newComment < 1) && ($_ ne /^\#|^--|^\/\/^\s*\/\*/|^\s*\*|\*\/ +$/)) { $out .= "#This file was updated with the fix"; $out .= "\n"; $newComment++; } $out .= $_; } open (OUT, '>output.txt'); print OUT $out or die "Can't print to OUT: $!"; close OUT; close IN; __DATA__ /* * This is the new function * It has the following parameters: * * 1. Filename * 2. URL */ # All the following are valid comment styles: # hello perl style -- hello sql style /* hello c style * continue c style end c style */ // c++ c style #Revision date: 2005-10-10 --start of file <-- here is where the new comment should go. configurationtype=search url=http://www.google.com --End of file

Replies are listed 'Best First'.
Re: inserting string only once after matching a pattern
by ikegami (Patriarch) on Nov 06, 2006 at 06:31 UTC
    Many problems:
    • You have an unescaped / in the regexp. Maybe you should use m{...} instead of /.../.
    • There's a | missing in the regexp.
    • The regexp would be more readable if you used the x option and added whitespace.
      if (! m{ foo | bar | baz }x ) { ... }
    • $_ ne /.../ should be $_ !~ /.../, !($_ =~ /.../) or just !/.../.
    • You read the file a line at a time, yet you have no flag telling you if you're in the middle of a multi-line /*...*/ comment.
    • Why do you accumulate the text in $out instead of printing as you go along?
      Thank You!

      I used the m{} syntax and fixed the regexp issues. I'm actually posting on a different computer from the code so the regexp issues were mistyping it.

      I'll study the different not equals soon. I didn't realize the the ne was the wrong syntax. I actually had (!~) initially but I read on a webpage that it's better to use "ne".

      At first I wasn't sure why I would need flag to determine if I'm in a multi-line /*...*/ comment. The syntax used in the files, always has a * as the first visible character in multi-line comments. Although you're right that it's not required. That's a nice catch. I haven't programmed in C in years.

      The only reason for accumulating the text is that the write commands are all together instead of spread out. The actual logic of the write operations take up a page of text and it's nice to treat the write operation as a single block. Since the files are small, avg. is 7k, and the largest are no more than 100k, memory is not a problem. Is this considered bad form in perl?

        I actually had (!~) initially but I read on a webpage that it's better to use "ne".

        When comparing against a constant strings, it's more efficient to avoid regexps.

        $var eq 'abc' $var ne 'abc' $var1 eq $var2 $var1 ne $var2
        are faster and simpler than
        $var =~ /^abc\z/ $var !~ /^abc\z/ $var1 =~ /^\Q$var2\z/ $var1 !~ /^\Q$var2\z/

        I'll study the different not equals soon.

        $var ne /regexp/
        means
        $var ne ($_ =~ /regexp/)

        • When matching against a regexp, use a match operator (=~ or !~).
        • When comparing strings, use a string comparison operator (eq, ne, lt, gt, le, ge or cmp).
        • When comparing numbers, use a numerical comparison operator (==, !=, <, >, <=, >= or <=>).
Re: inserting string only once after matching a pattern
by artist (Parson) on Nov 06, 2006 at 11:38 UTC
    You might want to use Regexp::Common to extract comments from the code.
    --Artist