【问题标题】:Extracting specific data from text file in Perl从 Perl 中的文本文件中提取特定数据
【发布时间】:2019-01-15 09:19:14
【问题描述】:

我是 Perl 新手,正在尝试从文件中提取特定数据,如下所示:

 Print of   9 heaviest strained elements:    


   Element no   Max strain 
      20004         9.6 % 
      20013         0.5 % 
      11189         0.1 % 
      20207         0.1 % 
      11157         0.1 % 
      11183         0.0 % 
      10665         0.0 % 
      20182         0.0 % 
      11160         0.0 % 


 ==================================================

我只想提取元素编号(20004、20013 等)并将它们写入新文件。文件的读取应在到达 (=========) 行后立即结束,因为稍后在文件中会有更多具有相同标题的元素编号。 希望这是有道理的。 非常感谢任何建议!

我现在有这个代码,它给了我一个数字列表,最多连续 10 个:

my $StrainOut = "PFP_elem"."_$loadComb"."_"."$i";
open DATAOUT, ">$StrainOut" or die "can't open $StrainOut";  # Open the file for writing.

open my $in, '<', "$POSTout" or die "Unable to open file: $!\n";
my $count = 0;

 while(my $line = <$in>) {
  last if $line =~ / ={10}\s*/;
  if ($line =~ /% *$/) {
    my @columns = split "         ", $line;
    $count++;
    if($count % 10 == 0) {
      print DATAOUT "$columns[1]\n";
    }
    else {
      print DATAOUT "$columns[1] ";
    }      
  }
}
close (DATAOUT);
close $in;

需要改变的是“my @columns = split...”这一行。目前,只要它有“9 个空格”,它就会拆分 $line 标量。由于元素编号的位数可能会有所不同,因此这是提取数据的一种不好的方法。是否可以只从左到右读取,省略所有空格并记录数字,直到数字后面跟着更多空格(这样百分比值被忽略)?

【问题讨论】:

  • 这似乎有效:我的@columns = split(/\s+/,$line);

标签: perl file


【解决方案1】:
#!/usr/bin/perl
use strict;
use warnings;

while (<>) {                        # read the file line by line
    if (/% *$/) {                   # if the line ends in a percent sign
        my @columns = split;        # create columns
        print $columns[0], "\n";    # print the first one
    }
    last if /={10}/;                # end of processing
}

【讨论】:

    【解决方案2】:

    使用触发器的单线:

    perl -ne '
      if ( m/\A\s*(?i)element\s+no/ .. ($end = /\A\s*=+\s*\Z/) ) {
        printf qq[$1\n] if m/\A\s*(\d+)/;
        exit 0 if $end
      }
    ' infile
    

    结果:

    20004
    20013
    11189
    20207
    11157
    11183
    10665
    20182
    11160
    

    【讨论】:

      【解决方案3】:
      #!/usr/bin/perl
      use strict;
      use warnings;
      
      while (my $f= shift) {
         open(F, $f) or (warn("While opening $f: $!", next);
         my foundstart=0;
        while(<F>) {
           ($foundstart++, next) if /^\s#Element/;
           last if /\s*=+/;
           print $_ if $foundstart;
        }
        $foundstart=0;
        close(F);
      }
      

      【讨论】:

      • 它有编译错误。 1.- warn 指令中缺少括号。 2.- 使用$foundstart 变量声明为标量,在下一个正则表达式中,我认为# 有错字,而不是*。然后它会在我的测试中打印数字和百分比。
      【解决方案4】:
      #!/usr/bin/perl
      use strict;
      use warnings;
      
      open my $rh, '<', 'input.txt' or die "Unable to open file: $!\n";
      open my $wh, '>', 'output.txt' or die "Unable to open file: $!\n";
      
      while (my $line = <$rh>) {        
          last if $line =~ /^ ={50}/;
          next unless $line =~ /^ {6}(\d+)/;
          print $wh "$1\n";
      }
      
      close $wh;
      

      【讨论】:

        【解决方案5】:

        您可以通过在命令 shell 中运行此单行代码来实现。

        在 *nix 上:

        cat in_file.txt | perl -ne 'print "$1\n" if ( m/\s*(\d+)\s*\d+\.\d+/ )' > out_file.txt
        

        在 Windows 上:

        type in_file.txt | perl -ne "print qq{$1\n} if ( m/\s*(\d+)\s*\d+\.\d+/ )" > out_file.txt
        

        【讨论】:

        • 他想在到达等号行时停止读取文件。
        • 猫是浪费进程。 -n 开关会导致对 @ARGV 中的文件名进行迭代,就像您编写了 LINE: while () { ...
        猜你喜欢
        • 1970-01-01
        • 2013-01-06
        • 2023-03-25
        • 1970-01-01
        • 2011-06-01
        • 1970-01-01
        • 2014-02-02
        • 2018-08-14
        • 1970-01-01
        相关资源
        最近更新 更多