【问题标题】:Perl,Move file handle in main and subroutinePerl,在主程序和子程序中移动文件句柄
【发布时间】:2018-07-15 03:18:59
【问题描述】:

脚本建议从 ASCII 文件中的某些数据表中提取某些值。

我修改了 script which I posted yesterday。 现在它几乎没有工作。我想知道以这种方式移动文件句柄是否是正确的方法。

用法还是一样

myscript.pl targetfolder/*> result.csv

F 是我的文件句柄。

我传递给子例程的参数是标量$_if 条件使用它。当我想在我的子程序中向下移动时next if 1..4不起作用,所以我重复$a = <F>;几次以实现向下移动文件句柄。

但我认为这不是在我的主代码和子例程中移动相同文件句柄的正确方法。我不确定它是否真的会通过每一行。我需要你的建议。

myscript.pl

#Report strip
use warnings;
use strict;

##Print the title 
Tfms2();

##Print the title 
print "\n";

@ff = <@ARGV>;

foreach $ff ( @ff ) {

    open (F, $ff);

    @fswf = @fschuck = @fsxpos = @fsypos = @fsdev = @csnom = ""; 
    @cswf = @cschuck = @csxpos = @csypos = @csnom = "";    # is there an efficient way?

    while (<F>) {
        Mfms2();
        Mfms3();
    }

    $r = 1;

    while ( $r <= $#fswf ) {      # because @fsws is the largest array
        Cfms3();   
        print "\n";
        $r++;
    }

    close (F);
}
##==========================================================================================
##Subs
##==========================================================================================

##FS II
sub Tfms2 {
    print "FS_Wafer,FS_ChuckID,FS_pos_X,FS_pos_Y,FS_deviation,CS_Wafer,CS_ChuckID,CS_pos_X,CS_pos_Y,CS_NofWafer_Ident_Spot";
}


sub Mfms2 {

    if ( /^F\sM\sSTATISTICS\sII$/ ) {

        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);

        $r = 1;

        @b = "";

        while ( $a !~ /\+\-/ ) {
            chomp $a;
            @b = split / *\| */, $a;

            $fswf[$r]    = $b[1];
            $fschuck[$r] = $b[2];
            $fsxpos[$r]  = $b[3];
            $fsypos[$r]  = $b[4];
            $fsdev[$r]   = $b[5];

            $r++;

            $a = (<F>);
            @b = "";
        }
    }
}


##FS III
sub Mfms3 {
    if ( /^F\sM\sSTATISTICS\sIII$/ ) {

        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);

        $r = 1;

        @b = "";

        while ( $a !~ /\+\-/ ) {
            chomp $a;
            @b = split / *\| */, $a;

            $cswf[$r]    = $b[1];
            $cschuck[$r] = $b[2];
            $csxpos[$r]  = $b[3];
            $csypos[$r]  = $b[4];
            $csnom[$r]   = $b[5];

            $r++;

            $a = (<F>);

            @b = "";
        }
    }
}


sub Cfms3 {
    print "$fswf[$r],$fschuck[$r],$fsxpos[$r],$fsypos[$r],$fsdev[$r],";
    print "$cswf[$r],$cschuck[$r],$csxpos[$r],$csypos[$r],$csnom[$r],";
}

【问题讨论】:

  • 上次,我要求您以后自己修复代码缩进。如果您懒得发布可读代码,我们为什么要努力帮助您?
  • 我传递给子程序的参数是一个标量 在这段代码中,你不会在任何地方向子程序传递任何东西。
  • 请在您在此处发布的代码上使用strictwarnings 编译指示。
  • @seedof:我看到您已编辑代码以添加 use strictuse warnings。因为您还没有进行任何其他修复,所以use strict 现在意味着您的代码甚至无法编译。请多加小心。
  • 你的程序甚至无法编译!

标签: perl filehandle


【解决方案1】:

您忘记告诉我们该程序应该做什么,因此很难提供任何帮助。您的上一个问题中可能包含更多信息,但我们并未在此处阅读所有问题,您甚至没有包含指向您上一个问题的链接。

您的问题的答案是您可以使用seek() 移动到文件中的任意位置。您可能还会发现查看 tell() 很有用,它可以告诉您当前在文件中的位置。

但我认为这些信息不会对您特别有帮助,因为您似乎对自己想要做什么感到很困惑。如果您要更详细地解释您的任务,那么我强烈怀疑我们可以帮助您(而且我还怀疑帮助主要涉及从头开始重写您的代码)。但在您向我们提供详细信息之前,我们所能做的就是指出您的代码中一些更明显的问题。

  • 您应该始终在代码中包含use strictuse warnings
  • 我认为@ff = &lt;@ARGV&gt; 不会像您认为的那样做。我想你想要@ff = @ARGV。而且,即便如此,这感觉就像你在毫无意义地抄袭@ARGV
  • 拥有同名的数组 (@ff) 和标量 ($ff) 有时会让人感到困惑。而且,更一般地说,您需要更加努力地明确命名变量。
  • 请使用open() 的三参数版本以及词法文件句柄。您还应该经常检查来自open() - open my $fh, "&lt;", $ff or die "Could not open $ff: $!" 的返回码。
  • @fswf=@fschuck=@fsxpos=@fsypos=@fsdev=@csnom="" 这样的行并没有按照您的想法进行。你最终会得到很多数组,每个数组都包含一个元素。最好只使用 my 声明数组 - Perl 会将它们创建为空 (my (@fswf, @fschuck, @fsxpos, ...))。
  • 如果您在读取文件时确实需要跳过八行,那么写起来会更清楚:$a = &lt;F&gt; for 1 .. 8
  • 您正在大量使用全局变量。这与软件工程最佳实践背道而驰是有充分理由的。它使您的代码比它需要的脆弱得多。

总而言之,您似乎在这里猜测解决方案,而这绝不是一个好方法。正如我上面所说,我们很乐意为您提供帮助,但如果没有更多信息,这几乎是不可能的。

更新:更仔细地查看您的代码,我发现您将从文件中解析的数据存储在多个数组中。每个数组都包含来自输​​入文件单列的数据,为了从单行获取所有数据,您需要使用相同的索引值访问这些数组中的每一个。这不是一个好主意。跨不同变量拆分链接数据是灾难的根源。一个更好的主意是将每条记录存储在一个散列中(其中的键表示存储的数据项)并将对所有这些散列的引用存储在一个数组中。这会将您的所有数据集中在一个变量中。

更新更新:我对您的数据了解得不够多,无法确定,但这是我会采取的方法。我只解析了数据,然后使用Data::Dumper 来显示解析后的数据结构。产生更好的输出留给读者作为练习:-)

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

use Data::Dumper;

@ARGV or die "Usage: $0 file [file...]\n";

# Define two list of keys for the different types
my %cols = (
  II  => [qw(wf chuck xpos ypos dev)],
  III => [qw(wf chuck xpos ypos nom)],
);

my @data;     # To store the parsed data
my $cur_type; # Keep track of the current type of record

while (<>) {
  # Look for a record header and determine which type of 
  # record we're dealing with (I think 'II' or 'III').
  if (/^F M STATISTICS (III?)$/) {
    $cur_type = $1;
    next;
  }

  # Skip lines that are just headers/footers
  next if /\+[-=]/;
  # Skip lines that don't include data
  next unless /\d/;

  chomp;

  # Remove the start and end of the line
  s/^\|\s+//;
  s/\s+\|$//;

  # Store the data in a hash with the correct keys 
  # for this type of record
  my %rec;
  @rec{@{$cols{$cur_type}}} = split /\s+\|\s+/;

  # Store a reference to our hash in @data
  push @data, \%rec;
}

# Dump the contents of @data
say Dumper \@data;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-14
    • 2012-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多