JohnnyP
JohnnyP

Reputation: 500

Find-Replace Multiple Occurrences of a string and append iterating number

How can I iterate over the code of an html file and find certain recurring text and then append a word and and iterating number to it.

So: 
<!-- TemplateBeginEditable -->
<!-- TemplateBeginEditable -->
<!-- TemplateBeginEditable -->   
etc...                    

Becomes :
<!-- TemplateBeginEditable Event=1 -->
<!-- TemplateBeginEditable Event=2 -->
<!-- TemplateBeginEditable Event=3 -->
etc...

I have tried PERL thinking it would be the easiest/fastest and went to jQuery and then back to PERL.

It seems simple enough to find/replace many ways with REGEX and return an array of the occurrences, but getting the iterating variable tacked on proves to be more of a challenge.

Latest Example of what I have tried:

#!/usr/bin/perl -w

# Open input file 
open INPUTFILE, "<", $ARGV[0] or die $!;
# Open output file in write mode
open OUTPUTFILE, ">", $ARGV[1] or die $!;

# Read the input file line by line
while (<INPUTFILE>) {
  my @matches = ($_ =~ m/TemplateBeginEditable/g);
  ### what do I do ith matches array? ###
  $_ =~ s/TemplateBeginEditable/TemplateBeginEditable Event=/g;
  print OUTPUTFILE $_; 

}


close INPUTFILE;
close OUTPUTFILE;

Upvotes: 0

Views: 106

Answers (4)

Jeff Y
Jeff Y

Reputation: 2456

If you have awk available, and the target text only occurs at most once per line, then Perl is overkill I think:

awk 'BEGIN{n=1}{n+=sub("TemplateBeginEditable","& Event="n)}1'

Some explanation: The sub function returns the number of substitutions performed (0 or 1); the & means "whatever matched"; "..."n is string concatenation (no operator in awk); the 1 is a "true" condition that invokes the default "action" of {print}.

Upvotes: 1

Jim Driscoll
Jim Driscoll

Reputation: 904

I'd just do:

local $/=undef;
my $content = <FH>;
my $x = 0;
$content =~ s/(My expected pattern)/$1 . " time=" . (++$x)/ge;

Upvotes: 0

Casimir et Hippolyte
Casimir et Hippolyte

Reputation: 89547

To perform a replacement, you don't need to match the pattern before, you can directly perform the replacement. Example with your code:

while (<INPUTFILE>) {
    s/TemplateBeginEditable/TemplateBeginEditable Event=/g;
    print OUTPUTFILE $_; 
}

Now to add a counter incremented at each replacement, you can put a piece of code in the pattern itself using this syntax:

my $i;

while (<INPUTFILE>) {
    s/TemplateBeginEditable(?{ ++$i })/TemplateBeginEditable Event=$i/g;
    print OUTPUTFILE $_; 
}

To make it shorter you can use the \K feature to change the start of the match result:

while (<INPUTFILE>) {
    s/TemplateBeginEditable\K(?{ ++$i })/ Event=$i/g;
    print OUTPUTFILE $_; 
}

Or with a one-liner:

perl -pe 's/TemplateBeginEditable\K(?{++$i})/ Event=$i/g' file > output

Upvotes: 1

Paul L
Paul L

Reputation: 938

Expanding on my one-liner in the comments:

#!/usr/bin/perl
use strict;
use warnings;

my $file = shift or die "Usage: $0 <filename>\n";

open my $fh, '<', $file or die "Cannot open $file: $!\n";
open my $ofh, '>', "$file.modified" or die "Cannot open $file.modified: $!\n";

my $i = 1;
while (my $line = <$fh>) {
   if ($line =~ s/TemplateBeginEditable/$& Event=$i/) {
      $i++;
   }
   print $ofh $line;
}

__END__

Note that this assumes you will never have more than one instance of your desired text on a single line, as shown in your sample input.

Upvotes: 0

Related Questions