Alternative to foreach hash loop in perl

I have two files: one with text and the other with key / hash values. I want to replace key occurrences with hash values. The following code does this, which I want to know if there is a better way than using the foreach loop that I use.

Thank you all

Edit: I know this is a little weird using

s/\n//; s/\r//; 

instead of chomp, but this works with files with mixed end-of-line characters (edited on both windows and linux) and chomp (I think) doesn't.

File with key / hash values ​​(hash.tsv):

 strict $tr|ct warnings w@rn |ng5 here h3r3 

File with text (doc.txt):

 Do you like use warnings and strict? I do not like use warnings and strict. Do you like them here or there? I do not like them here or there? I do not like them anywhere. I do not like use warnings and strict. I will not obey your good coding practice edict. 

Perl script:

 #!/usr/bin/perl use strict; use warnings; open (fh_hash, "<", "hash.tsv") or die "could not open file $!"; my %hash =(); while (<fh_hash>) { s/\n//; s/\r//; my @tmp_hash = split(/\t/); $hash{ @tmp_hash[0] } = @tmp_hash[1]; } close (fh_hash); open (fh_in, "<", "doc.txt") or die "could not open file $!"; open (fh_out, ">", "doc.out") or die "could not open file $!"; while (<fh_in>) { foreach my $key ( keys %hash ) { s/$key/$hash{$key}/g; } print fh_out; } close (fh_in); close (fh_out); 
+4
source share
2 answers

One problem with

 for my $key (keys %hash) { s/$key/$hash{$key}/g; } 

it does not handle correctly

 foo => bar bar => foo 

Instead of switching, you get all β€œfoo” or all β€œbar”, and you can't even control it.

 # Do once, not once per line my $pat = join '|', map quotemeta, keys %hash; s/($pat)/$hash{$1}/g; 

You can also process

 foo => bar food => baz 

taking the longest, and not ending with a "bard".

 # Do once, not once per line my $pat = join '|', map quotemeta, sort { length($b) <=> length($a) } keys %hash; s/($pat)/$hash{$1}/g; 
+2
source

You can read the whole file in a variable, replacing all occurrences at once for each -val key.

Sort of:

 use strict; use warnings; use YAML; use File::Slurp; my $href = YAML::LoadFile("hash.yaml"); my $text = read_file("text.txt"); foreach (keys %$href) { $text =~ s/$_/$href->{$_}/g; } open (my $fh_out, ">", "doc.out") or die "could not open file $!"; print $fh_out $text; close $fh_out; 

gives:

 Do you like use w@rn |ng5 and $tr|ct? I do not like use w@rn |ng5 and $tr|ct. Do you like them h3r3 or th3r3? I do not like them h3r3 or th3r3? I do not like them anywh3r3. I do not like use w@rn |ng5 and $tr|ct. I will not obey your good coding practice edict. 

To lock the code, I used YAML and replaced your input file:

 strict: $tr|ct warnings: w@rn |ng5 here: h3r3 

and used File :: Slurp to read the whole file into a variable. Of course, you can β€œpillage” a file without File :: Slurp, for example:

 my $text; { local($/); #or undef $/; open(my $fh, "<", $file ) or die "problem $!\n"; $text = <$fh>; close $fh; } 
+2
source

All Articles