· 7 years ago · Mar 02, 2019, 08:52 PM
1test1.txt
2
3porsche 430+turbo blue
4ferrari 520+supercharged red
5buggati 1001+supersport black
6fiat turbo white
7
8test2.txt
9turbo=30
10supercharged=50
11supersport=100
12
13output.txt
14 porsche 460 blue
15 ferrari 570 red
16 buggati 1101 black
17 fiat 30 white
18
19use strict;
20use warnings;
21use English qw( -no_match_vars );
22
23setup_for_testing( );
24
25open my $source_file, '<', 'text1.txt' || die "Couldn't open source file: $OS_ERROR";
26open my $key_file, '<', 'text2.txt' || die "Couldn't open key file: $OS_ERROR";
27
28# Clear the output file
29open my $output_file, '>', 'output.txt' || die "Couldn't open output file: $OS_ERROR";
30
31# Now open output file for append
32open $output_file, '>>', 'output.txt' || die "Couldn't open output file: $OS_ERROR";
33
34# Create translation map from text2.txt
35my %translation_map = translation_map( $key_file );
36
37# Process text1.txt and print to output.txt
38while ( my $source_line = <$source_file> ) {
39 my $transformed_line = transform( $source_line, %translation_map );
40 print $output_file $transformed_line ||
41 die "Couldn't print to output file: $OS_ERROR";;
42}
43
44# Tidy up
45close $source_file || die "Couldn't close source file: $OS_ERROR";
46close $key_file || die "Couldn't close key file: $OS_ERROR";
47close $output_file || die "Couldn't close output file: $OS_ERROR";
48
49###################
50sub setup_for_testing {
51 open my $textfile1, '>', 'text1.txt' || die "Couldn't open source file: $OS_ERROR";
52 open my $textfile2, '>', 'text2.txt' || die "Couldn't open key file: $OS_ERROR";
53
54 my $source_text =<<'END_TEXT';
55porsche 430-turbo blue
56ferrari 520*supercharged red
57buggati 1001+supersport black
58fiat turbo white
59END_TEXT
60
61 my $key_file_text =<<'END_TEXT';
62turbo=30
63supercharged=50
64supersport=100
65END_TEXT
66
67 print $textfile1 $source_text || die "Couldn't print to text1.txt: $OS_ERROR";
68 print $textfile2 $key_file_text || die "Couldn't print to text2.txt: $OS_ERROR";
69
70 close $textfile1 || die "Couldn't close source file: $OS_ERROR";
71 close $textfile2 || die "Couldn't close key file: $OS_ERROR";
72
73 return; # intentional void return
74}
75
76sub translation_map {
77 my $key_file = shift;
78
79 my %translation_map;
80 while ( my $key_mapping = <$key_file> ) {
81 chomp $key_mapping;
82
83 # The regex /x option allows whitespace in the regular expression for readability
84 my ( $key, $value ) = split / s* = s* /x, $key_mapping;
85 $translation_map{ $key } = $value;
86 }
87
88 return %translation_map;
89}
90
91sub transform {
92 my $source_line = shift @_;
93 my %value_for = %{ shift @_ };
94
95 my $transformed_line = $source_line;
96
97 foreach my $key ( keys %value_for ) {
98 # The regex /e option causes the rights side of a substitution to be evaluated as
99 # a Perl expression.
100 my $value = $value_for{ $key };
101 my ( $before_expression, $lvalue, $operator, $rvalue_key, $after_expression ) =
102 ( $transformed_line =~ m/ A
103 ( .*? )
104 ( d+ ) ([-+*/^]?) ( $key )
105 ( .* )
106 Z
107 /x );
108
109 if ( $operator ) {
110 my $rvalue = $value_for{ $rvalue_key };
111
112 # Using the dispatch table from amon's answer
113 my $value_of_expression = {
114 '+' => sub {$_[0] + $_[1]},
115 '-' => sub {$_[0] - $_[1]},
116 '*' => sub {$_[0] * $_[1]},
117 '/' => sub {$_[0] / $_[1]},
118 '^' => sub {$_[0] ** $_[1]},
119 }->{$operator}->($lvalue, $rvalue);
120
121 $transformed_line =
122 $before_expression . $value_of_expression . $after_expression . "n";
123 } else {
124 $transformed_line =~ s/$key/$value/;
125 }
126 }
127
128 return $transformed_line;
129}
130
131> ls
132stackoverflow-12169648_replace_value_of_key.pl
133
134> perl stackoverflow-12169648_replace_value_of_key.pl
135
136> ls
137output.txt text1.txt
138stackoverflow-12169648_replace_value_of_key.pl text2.txt
139
140> more text1.txt
141porsche 430+turbo blue
142ferrari 520+supercharged red
143buggati 1001+supersport black
144fiat turbo white
145
146> more text2.txt
147turbo=30
148supercharged=50
149supersport=100
150
151> more output.txt
152porsche 460 blue
153ferrari 570 red
154buggati 1101 black
155fiat 30 white
156
157my %variables = map {chomp; split /=/, $_, 2} do {
158 open my $file, "<", $filename_B or die;
159 <$file>;
160};
161
162while (defined(my $line = <$fileA>)) {
163 chomp $line;
164 my ($model, $expression, $color) = split /s+/, $line, 3;
165 my $value = parseExpression($expression);
166 print "t$model $value $colorn"; # use printf to prettyprint if needed
167}
168
169sub parseExpression {
170 my ($string) = @_;
171 my ($part, $operator, $rest) = ($string =~ /(w+)([-+*/^]?)(.*$)/g);
172 if (not $operator) {
173 # $part is the whole expression
174 my $value = exists $variables{$part} ? $variables{$part} : $part;
175 die if $value =~ /[a-z]/i; # The variable name was not substituted
176 return $value;
177 } else {
178 my $rval = parseExpression($rest);
179 my $lval = parseExpression($part); # you don't need this
180 # if there are no variables on the left
181 my $value = {
182 '+' => sub {$_[0] + $_[1]},
183 '-' => sub {$_[0] - $_[1]},
184 '*' => sub {$_[0] * $_[1]},
185 '/' => sub {$_[0] / $_[1]},
186 '^' => sub {$_[0] ** $_[1]},
187 }->{$operator}->($lval, $rval);
188 return $value;
189 }
190}
191
192expression ::= digits, operator, digits, { operator, digits }
193
194use strict;
195use warnings;
196
197my %values = do {
198 open my $fh, '<', 'test2.txt' or die $!;
199 local $/;
200 <$fh> =~ /w+/g;
201};
202
203my $regex = join '|', keys %values;
204
205open my $fh, '<', 'test1.txt' or die $!;
206
207while (<$fh>) {
208 s/b($regex)b/$values{$1}/g;
209 s|([0-9]+(s*[-+*/]s*[0-9]+)+)|$1|eeg;
210 print;
211}
212
213porsche 460 blue
214ferrari 570 red
215buggati 1101 black
216fiat 30 white
217
218{
219 "turbo" => 30,
220 "supercharged" => 50,
221 "supersport" => 100,
222}