1

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";
}
2
  • You didn't describe what issues you're facing Commented Oct 19, 2013 at 8:06
  • Edited questions.. I am not getting replace string. Commented Oct 19, 2013 at 8:09

5 Answers 5

4

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 
Sign up to request clarification or add additional context in comments.

1 Comment

Your code is looking very good. But I am not getting proper formatted output as my input file. Some extra space is coming in output file.
2

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!

Comments

1

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";

2 Comments

it's only replacing words of first line.
Your code is working but my formatting is getting messed up in output file .Extra space are coming after replaced words.Any idea?
1

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;
}

Comments

0
#!/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;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.