Susim Samanta
Susim Samanta

Reputation: 1593

How to replace string dynamically using perl script

I am trying to solve below issues.

I have 2 files. Address.txt and File.txt. I want to replace all A/B/C/D (File.txt) with corresponding string value (Read from Address.txt file) using perl script. It's not replacing in my output file. I am getting same content of File.txt. I tried below codes.

Here is Address.txt file

A,APPLE
B,BAL
C,CAT
D,DOG
E,ELEPHANT
F,FROG
G,GOD
H,HORCE

Here is File.txt

A B C
X Y X
M N O
D E F
F G H

Here is my code :

use strict;
use warnings;
open (MYFILE, 'Address.txt');

foreach (<MYFILE>){
    chomp;
    my @data_new = split/,/sm;
    open INPUTFILE, "<", $ARGV[0] or die $!;
    open OUT, '>ariout.txt' or die $!;
      my $src = $data_new[0];
    my $des = $data_new[1];

      while (<INPUTFILE>) {
          # print "In while :$src \t$des\n";
          $_ =~ s/$src/$des/g;
          print OUT $_; 
      }

      close INPUTFILE;
      close OUT;
      # /usr/bin/perl -p -i -e "s/A/APPLE/g" ARGV[0];
}
close (MYFILE);

If i Write $_ =~ s/A/Apple/g;

Then output file is fine and A is replacing with "Apple". But when dynamically coming it's not getting replaced.

Thanks in advance. I am new in perl scripting language . Correct me if I am wrong any where.

Update 1: I updated below code . It's working fine now. My questions Big O of this algo. Code :

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

open( my $out_fh, ">", "output.txt" ) || die "Can't open the output file for writing: $!";

open( my $address_fh, "<", "Address.txt" ) || die "Can't open the address file: $!";
my %lookup = map { chomp; split( /,/, $_, 2 ) } <$address_fh>;

open( my $file_fh, "<", "File1.txt" ) || die "Can't open the file.txt file: $!";
while (<$file_fh>) {
    my @line = split;
    for my $char ( @line ) {
        ( exists $lookup{$char} ) ? print $out_fh " $lookup{$char} " : print $out_fh " $char ";
    }
    print $out_fh "\n";
}

Upvotes: 1

Views: 6882

Answers (5)

somon
somon

Reputation: 1

#!/usr/bin/perl -w
# to replace multiple text strings in a file with text from another file

#select text from 1st file, replace in 2nd file
$file1 = 'Address.txt'; $file2 = 'File.txt';

# save the strings by which to replace
%replacement = ();
open IN,"$file1" or die "cant open $file1\n";
while(<IN>)
    {chomp $_;
    @a = split ',',$_;
    $replacement{$a[0]} = $a[1];}
close IN;

open OUT,">replaced_file";
open REPL,"$file2" or die "cant open $file2\n";
while(<REPL>)
    {chomp $_;
    @a = split ' ',$_; @replaced_data = ();
# replace strings wherever possible
    foreach $i(@a)
        {if(exists $replacement{$i}) {push @replaced_data,$replacement{$i};}
         else {push @replaced_data,$i;}
        }
    print OUT trim(join " ",@replaced_data),"\n";
    }
close REPL; close OUT;

########################################
sub trim
{
my $str = $_[0];
$str=~s/^\s*(.*)/$1/;
$str=~s/\s*$//;
return $str;
}

Upvotes: 0

Kenosis
Kenosis

Reputation: 6204

Here's another option that lets Perl handle the opening and closing of files:

use strict;
use warnings;

my $addresses_txt = pop;
my %hash = map { $1 => $2 if /(.+?),(.+)/ } <>;
push @ARGV, $addresses_txt;

while (<>) {
    my @array;
    push @array, $hash{$_} // $_ for split;
    print "@array\n";
}

Usage: perl File.txt Addresses.txt [>outFile.txt]

The last, optional parameter directs output to a file.

Output on your dataset:

APPLE BAL CAT
X Y X
M N O
DOG ELEPHANT FROG
FROG GOD HORCE

The name of the addresses' file is implicitly popped off of @ARGV for use later. Then, a hash is built, using the key/value pairs in File.txt.

The addresses' file is read, splitting each line into its single elements, and the defined-or (//) operator is used to returned the defined hash item or the single element, which is then pushed onto @array. Finally, the array is interpolated in a print statement.

Hope this helps!

Upvotes: 2

otokan
otokan

Reputation: 131

Your problem is that in every iteration of your foreach loop you overwrite any changes made earlier to output file.

My solution:

use strict;
use warnings;

open my $replacements, 'Address.txt' or die $!;

my %r;
foreach (<$replacements>) {
        chomp;
        my ($k, $v) = split/,/sm;
        $r{$k} = $v;
}
my $re = '(' . join('|', keys %r) . ')';

open my $input, "<", $ARGV[0] or die $!;

while (<$input>) {
        s/$re/$r{$1}/g;
        print;
}

Upvotes: 1

drmrgd
drmrgd

Reputation: 733

Not entirely sure how you want your output formatted. Do you want to keep the rows and columns as is?

I took a similar approach as above but kept the formatting the same as in your 'file.txt' file:

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

open( my $out_fh, ">", "output.txt" ) || die "Can't open the output file for writing: $!";

open( my $address_fh, "<", "address.txt" ) || die "Can't open the address file: $!";
my %lookup = map { chomp; split( /,/, $_, 2 ) } <$address_fh>;

open( my $file_fh, "<", "file.txt" ) || die "Can't open the file.txt file: $!";
while (<$file_fh>) {
    my @line = split;
    for my $char ( @line ) {
        ( exists $lookup{$char} ) ? print $out_fh " $lookup{$char} " : print $out_fh " $char ";
    }
    print $out_fh "\n";
}

That will give you the output:

 APPLE  BAL  CAT 
 X  Y  X 
 M  N  O 
 DOG  ELEPHANT  FROG 
 FROG  GOD  HORCE 

Upvotes: 4

Vorsprung
Vorsprung

Reputation: 34347

First, here is your existing program, rewritten slightly

open the address file

convert the address file to a hash so that the letters are the keys and the strings the values

open the other file

read in the single line in it

split the line into single letters

use the letters to lookup in the hash

use strict;
use warnings;

open(my $a,"Address.txt")||die $!;

my %address=map {split(/,/) } map {split(' ')} <$a>;

open(my $f,"File.txt")||die $!;

my $list=<$f>;

for my $letter (split(' ',$list)) {
  print $address{$letter}."\n" if (exists $address{$letter}); 
}

to make another file with the substitutions in place alter the loop that processes $list

for my $letter (split(' ',$list)) {
  if (exists $address{$letter}) {
      push @output, $address{$letter};
  }
  else { 
      push @output, $letter;
  }
}

open(my $o,">newFile.txt")||die $!;
print $o "@output";

Upvotes: 1

Related Questions