【问题标题】:Remove Line from File Based on Column Value in Perl根据 Perl 中的列值从文件中删除行
【发布时间】:2015-05-26 22:15:48
【问题描述】:

我希望遍历多个文件,以及文件中它们各自的行。我已经成功了。我现在想做的是根据其中一列中的数值删除文件中的行。

如果我有这样的输入:

 XP.sta1    -41.5166    0.0513    0.6842    0.1794    0  CPHI.BHZ   300.2458   -42.2436
 XP.sta2      3.5972    0.0500    0.7699    0.1213    0  E000.BHZ   300.5616     2.5545
 XP.sta3      3.7112    0.0267    0.7813    0.1457    0  E002.BHZ   300.6140     2.6160
 XP.sta4      4.2891    0.0214    0.6870    0.1308    0  E004.BHZ   301.2073     2.6006

第九列是我希望查看的列。我需要删除第 9 列中的该值(让我们为其分配一个变量 $time),如果 $time > 10 或小于 -10,则删除整行。到目前为止,我已经尝试过:

unless (($time < -10) || ($time > 10) {     
print OUT2 ($stlat,"  ",$stlon,"  ",$eqlat,"  ",$eqlong,"  ",$eqdepth,"  ",$time,"\n");
}}

但是我得到以下输出:

 XP.sta1    -41.5166    0.0513    0.6842    0.1794    0  CPHI.BHZ   300.2458   2.5545
 XP.sta2      3.5972    0.0500    0.7699    0.1213    0  E000.BHZ   300.5616    2.6160
 XP.sta3      3.7112    0.0267    0.7813    0.1457    0  E002.BHZ   300.6140     2.6006
 XP.sta4      4.2891    0.0214    0.6870    0.1308    0  E004.BHZ   301.2073 

如您所见,整行并没有被删除——只是满足真正的“除非”条件的值,然后其他值在第 9 列中向上移动。如何删除整行,而不仅仅是第九列号?

这里是我想编辑我的脚本的地方:

open(TABLEC,$File);
    @tablec = <TABLEC>;
    for ($j = 2; $j < $stop; $j++) {
       chomp ($tablec[$j]);
       ($netSta,$delayTime) = (split /\s+/,$tablec[$j])[1,9] ;  
        } 

在这个 for 循环中,我遍历每个文件,读取从 2 到 'stop' 的行,并切分返回字符。我将第 9 列设置为延迟时间变量。所以我循环遍历每一行,但我还不想打印任何东西(稍后在我的脚本中出现)。我只想删除整行,以便稍后在我的脚本中当我必须打印这些行时,第 9 列值为 >abs(10) 的行不存在。

【问题讨论】:

  • 我们需要查看您的其余代码
  • 如果范围的中点为 0,那么您可以使用 abs(正如 @Borodin 指出的那样),因此它可以短至 perl -anE 'say if abs $F[8] &lt;= 10 ;' datafile.txt

标签: perl


【解决方案1】:

我会跳过这行:

use warnings;
use strict; 

while(<DATA>){
    my @split = split;
    next if $split[8] > 10 or $split[8] < -10;
    print "$_\n";
}

 XP.sta2      3.5972    0.0500    0.7699    0.1213    0  E000.BHZ   300.5616     2.5545
 XP.sta3      3.7112    0.0267    0.7813    0.1457    0  E002.BHZ   300.6140     2.6160
 XP.sta4      4.2891    0.0214    0.6870    0.1308    0  E004.BHZ   301.2073     2.6006

【讨论】:

  • 嗨 Fugu,我对我需要做的事情的描述可能有点过于宽泛了。我想删除从 XP.sta1(第 0 列)开始到第 8 列的整行。然后,在第 8 列条件为真的那一行之后的所有行,向上移动。
  • 哦,真的!我忘记了下一个 if 运算符。我将在我的脚本中实现该运算符,以查看是否可以获得所需的输出。感谢您的帮助河豚。
  • 你好 fugu,我尝试实现下一个 if 语句;但是,在上面我编辑的 for 循环中,如果我使用 $tablec[9],它会引用第 9 行而不是第 9 列。关于如何引用第九列而不是第九行的任何想法?谢谢。
  • @user78872 你应该问一个新问题,但乍一看你的循环并没有按照你的想法做。
【解决方案2】:

您没有显示足够的代码来诊断问题,但是您的要求非常简单,就像这样完成

use strict;
use warnings;

while ( <DATA> ) {
  print unless abs((split)[8]) > 10;
}

__DATA__
 XP.sta1    -41.5166    0.0513    0.6842    0.1794    0  CPHI.BHZ   300.2458   -42.2436
 XP.sta2      3.5972    0.0500    0.7699    0.1213    0  E000.BHZ   300.5616     2.5545
 XP.sta3      3.7112    0.0267    0.7813    0.1457    0  E002.BHZ   300.6140     2.6160
 XP.sta4      4.2891    0.0214    0.6870    0.1308    0  E004.BHZ   301.2073     2.6006

输出

 XP.sta2      3.5972    0.0500    0.7699    0.1213    0  E000.BHZ   300.5616     2.5545
 XP.sta3      3.7112    0.0267    0.7813    0.1457    0  E002.BHZ   300.6140     2.6160
 XP.sta4      4.2891    0.0214    0.6870    0.1308    0  E004.BHZ   301.2073     2.6006

【讨论】:

  • @user78872:我看过,但不清楚你的意思是什么
【解决方案3】:

我认为您的问题已经得到解答,但这里有一些内容可以帮助您编辑内容

代码中的一些要点

  • 词法变量的标识符只能包含小写字母、十进制数字和下划线。大写字母为常量和包名等全局变量保留

  • 您应该使用词法文件句柄open三参数形式

  • 您应该始终验证open 是否成功。在失败的情况下,您的程序应该 die 并在 die 字符串中包含 $! 的值,以揭示为什么操作失败

    这些点一起意味着

    open(TABLEC, $File);
    

    变成

    open my $tablec_fh, '<', $File or die qq{Unable to open "$File" for input: $!};
    
  • 您可以使用chomp @tablec 一次chomp 整个数组

  • 您应该避免 C 风格的 for 循环,因为它很少是一个好的选择。 Perl 允许你迭代一个范围,你应该利用它。所以

    for ($j = 2; $j < $stop; $j++) { ... }
    

    变成

    for my $j ( 2 .. $stop-1 ) { ... }
    
  • split /\s+/ 应该几乎总是split ' '。后者是运算符的特殊情况,如果参数字符串有前导空格,它会阻止它返回初始空字段。如果您在没有任何参数的情况下调用split,则默认为split ' ', $_

这是对您的示例代码的重写,其中考虑了这些要点。我希望它比我之前的答案更合适

open my $tablec_fh, '<', $File or die qq{Unable to open "$File" for input: $!};
my @tablec = <$tablec_fh>;
chomp @tablec;
close $tablec_fh;

for my $i ( 2 .. $stop-1 ) {
  my $row = $tablec[$i];
  my ($net_sta, $delay_time) = (split ' ', $row)[0,8];
  next unless abs($delay_time) <= 10;

  # Do stuff with $row
} 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-06
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-10
    相关资源
    最近更新 更多