我想通过下面的for
循环从多个数据文件中删除空格。我在函数中插入了for
循环。该函数可以读取输入数据文件,但输出文件打印无法正常工作,除非我在每次打印到文件后重置变量($new_data
)。否则,较早的数据会附加到以后的数据中。另外,如果与输入和输出相同的文件有什么问题,因为我以后没有使用输入文件吗?
传递@row从inputFile读取,$ new_data用于写入outputFile
$dir = '/****/';
$inputFileSpring = $dir . "SpringSIMS.dat";
$inputFileSummer = $dir . "SummerSIMS.dat";
$inputFileFall = $dir . "FallSIMS.dat";
$outputFileSpring = $dir . "Spring.dat";
$outputFileSummer = $dir . "Summer.dat";
$outputFileFall = $dir . "Fall.dat";
#Read Spring SIMS Data
open (NOTE, "$inputFileSpring" || die "Could not open $inputFileSpring\n");
processFile(@row=<NOTE>);
close(NOTE);
#Write Spring Data
open(NOTE, ">$outputFileSpring" || die "Could not open $inputFileSpring\n");
print NOTE $new_data;
close(NOTE);
reset('new_data');
#Read Summer SIMS Data
open (NOTE, "$inputFileSummer" || die "Could not open $inputFileSummer\n");
processFile(@row=<NOTE>);
close(NOTE);
#Write Summer Data
open(NOTE, ">$outputFileSummer" || die "Could not open $inputFileSummer\n");
print NOTE $new_data;
close(NOTE);
reset('new_data');
#Read Fall SIMS Data
open (NOTE, "$inputFileFall" || die "Could not open $inputFileFall\n");
processFile(@row=<NOTE>);
close(NOTE);
#Write Fall Data
open(NOTE, ">$outputFileFall" || die "Could not open $inputFileFall\n");
print NOTE $new_data;
close(NOTE);
reset('new_data');
sub processFile
{
for $row(@row) {
chop($row);
@field = split(/\|/, $row);
for ($i=0; $i<@field; $i++) {
if ($field[$i] =~ /^ /)
{
$field[$i] = " ";
}
else
{
$field[$i] =~ s/ *$//g;
}
$new_data .= $field[$i] . "|";
}
$lastchar = chop($new_data);
if (@field == 15) {
$new_data .= "|0";
}
$new_data .= "\n";
}
# return $new_data;
} # END sub processFile
exit;
答案 0 :(得分:3)
Wowzers。那么,你的主问题是你正在使用全局变量。作为一般规则,你应该只使用全局变量......好吧,从不,真的。当然不是像这样的简单案例。
如果对变量使用词法范围,并将参数传递给子例程,您将永远不会注意到这样的问题。 E.g:
my $foo = process($bar);
sub process {
my $arg = shift;
my $value = ....;
return $value;
}
现在,我不禁注意到在每种情况下你都执行完全相同的open
,所以为什么不将它包含在你的子程序中。作为一个好处,您不必担心关闭文件句柄,因为它们在超出范围时会自动关闭。
不确定你的$last_char
变量是什么,所以我把它留作词汇。除了修复残暴的缩进之外,我对你的子程序中的代码一无所知。代码中的显着变化:
strict
和warnings
!chop
- &gt; chomp
。你基本上不应该使用chop
。open
,使用显式模式和词法文件句柄。 注意:您应该从不编写perl代码而不使用use strict; use warnings;
。没有使用它们没有任何好处:你只会花更多的时间来寻找简单的错误。
注意#2:未经测试的代码
use strict;
use warnings;
my @seasons = ("Spring", "Summer", "Fall");
for my $season (@seasons) {
my $input = $season . "SIMS.dat";
my $output = $season . ".dat";
output_data($input, $output);
}
sub processFile {
my $file = shift;
open my $fh, '<', $file or die "$file: $!";
while (my $row = <$fh>) {
chomp $row; # NOTE: never use chop, use chomp instead
my @field = split(/\|/, $row);
for (my $i=0; $i<@field; $i++){
if ($field[$i] =~ /^ /) {
$field[$i] = " ";
} else {
$field[$i] =~ s/ *$//g;
}
}
my $new_data = join "|", @field;
if(@field == 15) {
$new_data .= "|0";
}
$new_data .= "\n";
}
return $new_data;
}
sub output_data {
my ($input, $output) = @_;
open my $fh, '>', $output or die "$output: $!";
print $fh processFile($input);
}
ETA:现在查看您的子程序代码,我发生了以下优化:
$new_data .= $field[$i] . "|";
....
my $lastchar = chop($new_data);
没有。而是使用join
:
$new_data = join "|", @field;
这部分:
if ($field[$i] =~ /^ /) {
$field[$i] = " ";
} else {
$field[$i] =~ s/ *$//g;
}
...将 将第一个字段更改为单个空格" "
,如果第一个字符是空格,或它将从中删除空格字符串的结尾。这真的你想要什么?即" foo"
将更改为" "
(空格)。
我想你会像以下那样:
$field[$i] =~ s/^ *//;
$field[$i] =~ s/ *$//;
在这种情况下,你可以简单地做:
for (@field) {
s/^ *//;
s/ *$//;
}
这是按预期工作的,因为$_
对数组中的每个元素都有别名,并且它们将被替换正则表达式更改。一个更详细的解决方案:
for my $value (@field) {
$value =~ s/^ *//;
$value =~ s/ *$//;
}
或者,更好的是,您可以在split
声明中包含此内容:
my $new_data = join "|", split /\s*\|\s*/, $row;
$new_data =~ s/^ *//;
$new_data =~ s/ *$//;
或使用正则表达式,这可能会更便宜:
$row =~ s/\s*\|\s*/|/g;
$row =~ s/^ *//;
$row =~ s/ *$//;
my $new_data = $row;
答案 1 :(得分:0)
因为您使用$ new_data变量作为全局变量,并且所有分配都是追加分配,这会导致您的数据在不清除的情况下建立。
因此,为了在不调用复位的情况下处理此问题,您可以将清算放在子程序中,因此每次调用子程序时,它都会自动清除它。
sub processFile
{
$new_data = ""; #this should empty it out
for $row(@row) {
chop($row);
@field = split(/\|/, $row);
for ($i=0; $i<@field; $i++){
if ($field[$i] =~ /^ /)
{
$field[$i] = " ";
}
else
{
$field[$i] =~ s/ *$//g;
}
$new_data .= $field[$i] . "|";
}
$lastchar = chop($new_data);
if(@field == 15) {
$new_data .= "|0";
}
$new_data .= "\n";
}
# return $new_data;
} # END sub processFile
这样,无论何时运行该函数,它都应该清除它,因此您不必手动执行此操作。
答案 2 :(得分:0)
Perl reset
函数的任何使用都是陈旧的,但您的使用也是错误的。如果你想删除$new_data
的内容,只需说出一个
$new_data = '';
$new_data = undef;
undef $new_data;
reset('new_data')
实际上做的是删除以字母'a','d','e','n','t','w'或'_开头的所有符号(*) ”。
(*) - 它不会删除词法变量,但是这个脚本没有任何这些变量。