Home > Net >  How to search and replace a word on multiple occurrence
How to search and replace a word on multiple occurrence

Time:09-17

Can anyone please tell me how can I search a word in a text file and replace first 2 occurrences with one value and next 2 occurrences with another value and so on using perl script? Is that possible? Below command just replaces all cat1, cat2, cat3 etc. to dog1, but I want to replace cat1,cat2 to dog1 and cat3, cat4 to dog3.

s/cat[0-9]/dog1/g;

Below is the script that I have tried:

#!/usr/bin/perl -w

use strict;

my $file = 'C:\Temp\test.txt';
rename($file, $file . '.bak');
open(IN, '<' . $file . '.bak') or die $!;
open(OUT, '>' . $file) or die $!;
while(<IN>)
{
    $_ =~ s/cat[0-9]/dog1/g;
    print OUT $_;
}
close(IN);
close(OUT);

Input:

Replacement value1: dog51
Replacement value2: dog23
Replacement value3: dog77
Replacement value4: dog95

Existing File:

<some texts>
test cat01 text
test cat32 text
test cat83 text
test cat54 text
test cat92 text
test cat13 text
test cat62 text
test cat23 text

File after replacement:

<some texts>
test dog51 text
test dog51 text
test dog23 text
test dog23 text
test dog77 text
test dog77 text
test dog95 text
test dog95 text

CodePudding user response:

Refer to s/// (especially the e modifier). This replaces even numbers with N-1.

use warnings;
use strict;

while (<DATA>) {
    s/cat(\d )/sprintf 'dog
', ($1 % 2) ? $1 : ($1-1)/e;
    print;
}

__DATA__
cat1
cat2
cat3
cat4
cat5
cat6

Prints:

dog1
dog1
dog3
dog3
dog5
dog5

(\d ) captures the digits after cat and stores them in the $1 variable which is used on the right side of the substitution.


After an update to the Question, it looks like the replacement values should be random:

use warnings;
use strict;

my $cnt = 0;
my $n;
while (<DATA>) {
    if (/cat\d/) {
        $cnt = ($cnt) ? 0 : 1;
        $n = randint() if $cnt;
        s/cat(\d )/dog$n/;
    }
    print;
}

sub randint {
    return sprintf 'd', int rand 100;
}

__DATA__
test cat01 text
test cat32 text
test cat83 text
test cat54 text
test cat92 text
test cat13 text
test cat62 text
test cat23 text

Prints:

test dog38 text
test dog38 text
test dog46 text
test dog46 text
test dog98 text
test dog98 text
test dog59 text
test dog59 text

A different set of numbers will be displayed each time the code is run.

CodePudding user response:

According OP there is no correlation in input and output numbering.

In such situation probable solution is hash mapping input values to output values.

use strict;
use warnings;

my %hash = (
        'cat1' => 'dog1',
        'cat2' => 'dog1',
        'cat3' => 'dog3',
        'cat4' => 'dog3'
    );

while( my $line = <DATA> ) {
    $line =~ s/\b($_)\b/$hash{$1}/g for keys %hash;
    print $line;
}

__DATA__
some sentence cat1 goes here
some cat3 sentence goes here
some sentence goes cat1 here
some sentence cat34 goes here
cat4 some sentence goes here

Output

some sentence dog1 goes here
some dog3 sentence goes here
some sentence goes dog1 here
some sentence cat34 goes here
dog3 some sentence goes here

Sample code for predefined double replacement (for problem description in altered question)

use strict;
use warnings;

my($index,$counter) = (-1,-1);

my @input = (
        'Replacement value1: dog51',
        'Replacement value2: dog23',
        'Replacement value3: dog77',
        'Replacement value4: dog95'
    );
    
@input = map { s/Replacement value\d: // && $_ } @input;

while( my $line = <DATA> ) {
    if( $line =~ /cat\d{2}/ ) {
          $index unless   $counter%2;
        $line =~ s/\bcat\d{2}\b/$input[$index]/;
    }
    print $line;
}

__DATA__
<some texts>
test cat01 text
test cat32 text
test cat83 text
test cat54 text
test cat92 text
test cat13 text
test cat62 text
test cat23 text
<some text>

Output

<some texts>
test dog51 text
test dog51 text
test dog23 text
test dog23 text
test dog77 text
test dog77 text
test dog95 text
test dog95 text
<some text>
  •  Tags:  
  • perl
  • Related