用第二个csv文件中的字符串替换substring

时间:2012-07-13 13:11:48

标签: perl

之前我正在循环中进行循环,如果匹配,它将替换第二个循环文件​​中的整个字符串。现在我的情况略有不同。我试图用第二个循环中的字符串替换第一个循环中的子字符串。它们都是csv文件和分号分隔的。我试图替换的是特殊字符:从数字代码到字符本身第一个文件看起来像:

1;2;bla&#322blabla &#261bla;7;8
3;4;bl&#261blabla;9;10
2;3;blablabla&#261ał8;9

,第二个文件包含数字代码和相应的字符:

Ą;Ą
ą;ą
Ǟ;Ǟ
Á;Á
á;á
Â;Â
ł;ł

第二个文件中的第一个分号属于相应字符的数字代码,不应用于拆分文件。结果应该是:

1;2;blałblabla ąbla;7;8
3;4;bląblabla;9;10
2;3;blablablaąał;8;9

这是我的代码。我该如何解决这个问题?

use strict;
use warnings;

my $inputfile1 = shift || die "input/output!\n";
my $inputfile2 = shift || die "input/output!\n";
my $outputfile = shift || die "output!\n";

open my $INFILE1,  '<', $inputfile1 or die "Used/Not found :$!\n";
open my $INFILE2,  '<', $inputfile2 or die "Used/Not found :$!\n";
open my $OUTFILE, '>', $outputfile or die "Used/Not found :$!\n";

my $infile2_pos = tell $INFILE2;

while (<$INFILE1>) {
s/"//g;
my @elements = split /;/, $_;
seek $INFILE2, $infile2_pos, 0;

    while (<$INFILE2>) {
    s/"//g;
    my @loopelements = split /;/, $_;

    #### The problem part ####
    if (($elements[2] =~ /\&\#\d{3}\;/g) and (($elements[2]) eq ($loopelements[0]))){
        $elements[2] =~ s/(\&\#\d{3}\;)/$loopelements[1]/g;
        print "$2. elements[2]\n";
                }
    #### End problem part #####
    }

my $output_line = join(";", @elements);
print $OUTFILE $output_line;
#print "\n"
}

close $INFILE1;
close $INFILE2;
close $OUTFILE;

exit 0;

2 个答案:

答案 0 :(得分:2)

假设您的字符代码是标准的Unicode实体,最好使用HTML::Entities对其进行解码。

此程序处理您在第一个文件中显示的数据,并完全忽略第二个文件。输出似乎是你想要的。

use strict;
use warnings;

use HTML::Entities 'decode_entities';

binmode STDOUT, ":utf8";

while (<DATA>) {
  print decode_entities($_);
}

__DATA__
1;2;bla&#322blabla &#261bla;7;8
3;4;bl&#261blabla;9;10
2;3;blablabla&#261a&#322;8;9

<强>输出

1;2;blałblabla ąbla;7;8
3;4;bląblabla;9;10
2;3;blablablaąał8;9

答案 1 :(得分:0)

您在每次@elements出现时都会将;拆分,然后将其删除。您不会在数据中找到它,Regexp中的分号永远不会匹配,因此不会进行任何替换。

无论如何,使用seek对我来说有点令人不安。由于您有合理数量的替换代码(&lt; 5000),您可以考虑将它们放入哈希:

my %subst;
while(<$INFILE2>){
    /^&#(\d{3});;(.*)\n/;
    $subst{$1} = $2;
}

然后我们可以这样做:

while(<$INFILE1>){
   s| &# (\d{3}) | $subst{$1} // "&#$1" |egx;
       # (don't try to concat undef
       # when no substitution for our code is defined)
   print $OUTFILE $_;
}

如果在INFILE1中的任何地方都要进行替换,我们不必拆分文件或将其视为CSV数据。我的解决方案应该加快一点(仅解析INFILE2一次)。在这里,我假设您的输入数据是正确的,数字代码不是以分号结尾,而是按长度终止。您可能希望从正则表达式中删除它。(即m/&#\d{3}/

如果您在使用字符编码时遇到问题,可能需要使用以下命令打开文件:uft8和/或use Encode或类似文件。