Perl 替换 - 查找 table 问题

Perl substitution - lookup table issue

我有一个大约 35MB 的 KML 文件,其中所有地标都命名为 "kml1234" 等。我想用 "Area 9987" 之类的可读字符串替换名称,并且我有查找 table。我在这里 () 找到了一段 perl,它适用于大多数地标。但是,我发现它在特定情况下失败了。这是代码。

$repl{kml1} = "Area A";
$repl{kml12} = "Area B";
$repl{kml123} = "Area C";
$repl{kml69} = "Area D";
$repl{kml4458} = "Area E";

$s = <<HEADER;
$start = time;
open(F, "input.txt");
open(OUTPUT, ">output.txt");
while (<F>) {
HEADER

foreach $key (keys %repl) {
   $s .= "s/$key/$repl{$key}\/;\n"
}

$s .= <<FOOTER;
print $_;
}
close(F);
close(OUTPUT);
print "Elapsed time (eval.pl): " . (time - $start) . "\r\n";
FOOTER

eval $s;

我已经使用测试字符串(放入 input.txt)单独测试了它:

<Placemark id="kml123">

预期的结果是:

<Placemark id="Area C">

但是,如果我使用相同的输入 (kml123) 再次 运行 脚本,我会得到以下 3 个结果中的任何一个:

<Placemark id="Area A23">
<Placemark id="Area B3">
<Placemark id="Area C">

似乎这种替代有时会以某种方式 t运行cating $key 到 kml1 或 kml12?我注意到我从来没有得到预期的 "Area D" 或 "Area E",我怀疑这是因为它们与 kml123 不够相似,只是前 3 个。有什么线索吗?

本程序的核心是使用Perl的正则表达式。问题是 Perl kml1 作为搜索字符串(s/// 表达式的第一部分)匹配 kml123。如果您将 search/replace 更改为以下内容:

s/"$key">$/"$repl{$key}"/; 

它将起作用,因为它只有在完全匹配的模式用引号引起来时才会匹配。

有点想,但阅读this page on regular expressions will make you a master at them. Playing games like regex golf也会帮助你提高技能,更有效地解决这个问题。

@ahjohnston25 的回答中已经提到了主要问题,但是你接管了带有评估和模糊内容的丑陋代码,所以我让它变得更简单和更清晰:

#!/usr/bin/perl

use strict; use warnings; use autodie;

my %repl = (
  "kml1" => "Area A",
  "kml12" => "Area B",
  "kml123" => "Area C",
  "kml69" => "Area D",
  "kml4458" => "Area E",
);

open( my $F, '<', "input.txt" );
open( my $OUTPUT, '>', "output.txt" );

while ( <$F> ) {
  foreach my $key ( sort keys %repl ) {
     s/\b$key\b/$repl{$key}/g;
  }
  print $OUTPUT $_; 
}

close( $F );
close( $OUTPUT );

我希望在这种形式下更容易理解正在发生的事情。