Perl替换 - 查找表问题

时间:2015-02-14 02:02:13

标签: regex perl hashtable lookup substitution

我有一个~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个。任何线索?

2 个答案:

答案 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这样的游戏也可以帮助您提高技能并更有效地解决这些问题。