考虑下面的数据集。每个以数字开头的块都是“案例”。在真实的数据集中,我有成千上万的案例。如果案例中只有一个词排除(例如案例10001),我想将“排除”一词改为“0”。
如果我遍历行,我可以计算每种情况下有多少“排除”。但是,如果只有一行包含“排除”一词,我不知道如何回到该行并替换该词。
我该怎么做?
10001
M1|F1|SP1;12;12;12;11;13;10;Exclusion;D16S539
M1|F1|SP1;12;10;12;9;11;9;3.60;D16S
M1|F1|SP1;12;10;10;7;11;7;20.00;D7S
M1|F1|SP1;13;12;12;12;12;12;3.91;D13S
M1|F1|SP1;11;11;13;11;13;11;3.27;D5S
M1|F1|SP1;14;12;14;10;12;10;1.99;CSF
10002
M1|F1|SP1;8;13;13;8;8;12;2.91;D16S
M1|F1|SP1;13;11;13;10;10;10;4.13;D7S
M1|F1|SP1;12;9;12;10;11;16;Exclusion;D13S
M1|F1|SP1;12;10;12;10;14;15;Exclusion;D5S
M1|F1|SP1;13;10;10;10;17;18;Exclusion;CSF
答案 0 :(得分:4)
sub process_block {
my ($block) = @_;
$block =~ s/\bExclusion\b/0/
if $block !~ /\bExclusion\b.*\bExclusion\b/s;
print($block);
}
my $buf;
while (<>) {
if (/^\d/) {
process_block($buf) if $buf;
$buf = '';
}
$buf .= $_;
}
process_block($buf) if $buf;
答案 1 :(得分:2)
在阅读文件时,缓冲案例中的所有行,并计算排除项
my ($case,$buf,$count) = (undef,"",0);
while(my $ln = <>) {
使用正则表达式来检测案例,
if( $ln =~ /^\d+$/ ) {
#new case, process/print old case
$buf =~ s/;Exclusion;/;0;/ if($count==1);
print $buf;
($case,$buf,$count) = ($ln,"",0);
}
现在使用正则表达式检测“排除”?
elsif( $ln =~ /;Exclusion;/ ) { $count++; }
$buf .= $l;
}
当你完成后,你可能还有一个案件需要处理,
if( length($buf)>0 ) {
$buf =~ s/;Exclusion;/;0;/ if($count==1);
print $buffer;
}
答案 2 :(得分:1)
这是我能想到的最好的。假设您将文件读入@lines
# separate into blocks
foreach my $line (@lines) {
chomp($line);
if ($line =~ m/^(\d+)/) {
$key = $1;
}
else {
push (@{$block{$key}}, $line);
}
}
# go through each block
foreach my $key (keys %block) {
print "$key\n";
my @matched = grep ($_ =~ m/exclusion/i, @{$block{$key}});
if (scalar (1 == @matched)){
foreach my $line (@{$block{$key}}) {
$line =~ s/Exclusion/0/i;
print "$line\n";
}
}
else {
foreach my $line (@{$block{$key}}) {
print "$line\n";
}
}
}
答案 3 :(得分:1)
这里已经有很多正确答案,它们使用缓冲区来存储“案例”的内容。
这是使用tell
和seek
来回放文件的另一种解决方案,因此不需要缓冲区。当您的“案例”非常大并且您对性能或内存使用敏感时,这可能很有用。
use strict;
use warnings;
open FILE, "text.txt";
open REPLACE, ">replace.txt";
my $count = 0; # count of 'Exclusion' in the current case
my $position = 0;
my $prev_position = 0;
my $first_occur_position = 0; # first occurence of 'Exclusion' in the current case
my $visited = 0; # whether the current line is visited before
while (<FILE>) {
# keep track of the position before reading
# the current line
$prev_position = $position;
$position = tell FILE;
if ($visited == 0) {
if (/^\d+/) {
# new case
if ($count == 1) {
# rewind to the first occurence
# of 'Exclusion' in the previous case
seek FILE, $first_occur_position, 0;
$visited = 1;
}
else {
print REPLACE $_;
}
}
elsif (/Exclusion/) {
$count++;
if ($count > 1) {
seek FILE, $first_occur_position, 0;
$visited = 1;
}
elsif ($count == 1) {
$first_occur_position = $prev_position;
}
}
else {
print REPLACE $_ if ($count == 0);
}
if (eof FILE && $count == 1) {
seek FILE, $first_occur_position, 0;
$visited = 1;
}
}
else {
if ($count == 1) {
s/Exclusion/0/;
}
if (/^\d+/) {
$position = tell FILE;
$visited = 0;
$count = 0;
}
print REPLACE $_;
}
}
close REPLACE;
close FILE;