adhi .b
adhi .b

Reputation: 341

How to interpolate the escape characters stored in a variable in perl?

I have written a perl code to get the source filename ,destination filename, pattern and replacement string.The below one is the code I have written.

chomp($input=<stdin>);   #source file name.
open SRC, $input;        #opening the file .

chomp($input=<stdin>);   #destination file name.
open DES, ">>$input";     #opening the file.

chomp($pattern=<stdin>);   #pattern to be matched.

chomp($replace=<stdin>);   #replacement string.

while(<SRC>){
    s/$pattern/$replace/g;
    print DES $_;
}

I have written this code to replace the particular value in a file and store it in another file. As per the code if I have given the pattern " "(white space) and replacement string as \n ,it should give the output as follows.

Sample Input

Hai hello this for testing .

sample output

Hai 
hello
this
for
testing
.

But it has given the output as follows.

Output

hai\nhello\nthis\nis\nfor\ntesting\n.

Please help me to solve this problem.

Upvotes: 2

Views: 206

Answers (2)

Borodin
Borodin

Reputation: 126722

Please, you must always use strict and use warnings 'all' at the top of every Perl program you write, end declare every variable with my. You should also use lexical file handles and the three-parameter form of open, and always check that a call to open has succeeded. So

open DES, ">>$input"

should be more like

open my $des_fh, '>>', $input or die qq{Unable to open "$input" for appending: $!}



You could use eval for this, but it's much cleaner and safer to use the String::Interpolate module, which provides access to the code within perl that processes double-quoted strings. It exports The interpolate function, which will correctly translate all variable references as well as any special characters like \n or \t

It would look like this

use strict;
use warnings 'all';

use String::Interpolate 'interpolate';

chomp( my $in_file = <> );
open my $in_fh, '<', $in_file or die qq{Unable to open "$in_file" for input: $!};

chomp( my $out_file = <> );
open my $out_fh, '>>', $out_file or die qq{Unable to open "$out_file" for input: $!};

chomp( my $pattern = <> );

chomp( my $replace = <> );
$replace = interpolate($replace);

while ( <$in_fh> ) {
    s/$pattern/$replace/g;
    print $out_fh $_;
}

Note that you could enter the parameters on the command line instead of having your program prompt for them

use strict;
use warnings 'all';

use String::Interpolate 'interpolate';

my $pattern = shift;
my $replace = shift;
$replace = interpolate($replace);

print s/$pattern/$replace/gr while <>;

You would call this like so

$ perl replace.pl ' '  '\n'  sample.txt

and you can redirect the output to a file in the normal way

$ perl replace.pl ' '  '\n'  sample.txt > output.txt

Upvotes: 7

ikegami
ikegami

Reputation: 385655

I strongly recommend the functions provided by String::Substitution.

Replace

s/$pattern/$replace/g;

with

use String::Substitution qw( gsub_modify );

gsub_modify($_, $pattern, $replace);

This won't just handle \n; it'll handle $1 too!


Notes:

  • There is a lot of advice to use eval EXPR (sometimes disguised as /ee), but this is very error-prone and dangerous.

  • In the past, I've provided solutions that use String::Interpolate, but the module provides an extremely weird interface.

Upvotes: 1

Related Questions