Perl中输出的函数参数

时间:2012-02-15 21:46:45

标签: perl

我想通过下面的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;

3 个答案:

答案 0 :(得分:3)

Wowzers。那么,你的问题是你正在使用全局变量。作为一般规则,你应该只使用全局变量......好吧,从不,真的。当然不是像这样的简单案例。

如果对变量使用词法范围,并将参数传递给子例程,您将永远不会注意到这样的问题。 E.g:

my $foo = process($bar);

sub process {
    my $arg = shift;
    my $value = ....;
    return $value;
}

现在,我不禁注意到在每种情况下你都执行完全相同的open,所以为什么不将它包含在你的子程序中。作为一个好处,您不必担心关闭文件句柄,因为它们在超出范围时会自动关闭。

不确定你的$last_char变量是什么,所以我把它留作词汇。除了修复残暴的缩进之外,我对你的子程序中的代码一无所知。代码中的显着变化:

  • 使用strictwarnings
  • 使用返回值,返回词法范围变量的值
  • 将参数传递给子程序
  • 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'或'_开头的所有符号(*) ”。

(*) - 它不会删除词法变量,但是这个脚本没有任何这些变量。