我有一个~35MB的KML文件,其中所有地标都被命名为" kml1234"等等。我想用一个可读的字符串替换名称,例如" Area 9987"我有查找表。我在这里找到了一个perl片段(https://stackoverflow.com/a/6435950),它适用于大多数地标。但是,我发现它在特定情况下失败了。这是代码。
$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">
似乎替代品有时会将$ key截断为kml1或kml12?我注意到我从未得到过&#34; D区&#34;或&#34; E区&#34;这是预期的,我怀疑这是因为它们与kml123不太相似,只是第3个。任何线索?
答案 0 :(得分:4)
在@ 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 );
我希望在这种形式下,更容易理解正在发生的事情。
答案 1 :(得分:1)
该程序的核心使用Perl的正则表达式。问题是Perl kml1
作为搜索字符串(s///
表达式的第一部分)与kml123
匹配。如果您将搜索/替换更改为以下内容:
s/"$key">$/"$repl{$key}"/;
它将起作用,因为它只会匹配精确的模式被引号括起来。
有点想一想,但在正则表达式上阅读this page会让你成为他们的主人。玩像regex golf这样的游戏也可以帮助您提高技能并更有效地解决这些问题。