2016-01-13 94 views
1

我寫了一個簡短的腳本來轉換我的數據(從輸入文件到輸出)。我停下來,當我應該只提取這些線能量negatove(每行的最後一個值)。Perl - 從文件中排除一些行

我的輸入數據是:

ATOM 367 OH2 HOH 367  -2.010 7.370 -7.369 -6.52 
ATOM 491 OH2 HOH 491  0.990 8.370 -8.369 -2.24 
ATOM 652 OH2 HOH 652  5.490 -6.130 2.631 2.98 
ATOM 689 OH2 HOH 689  6.490 -15.130 8.631 -4.23 
ATOM 738 OH2 HOH 738  7.490 19.870 -8.369 3.38 
ATOM 793 OH2 HOH 793  8.990 -2.630 -22.869 -2.29 
ATOM 857 OH2 HOH 857  10.490 13.370 -5.869 -1.31 
. 
. 
. 

我的輸出數據是這樣的:

moja woda t= 0 
     1 
     1SOL  OW 1 -0.344 0.437 0.633 -9.290 
    20.0 20.0 20.0 
    moja woda t= 1 
     1 
     1SOL  OW 1 -0.194 0.537 -0.767 -2.990 
    20.0 20.0 20.0 
    moja woda t= 2 
     1 
     1SOL  OW 1 -0.044 0.287 0.333 4.960 
    20.0 20.0 20.0 
    moja woda t= 3 
     1 
     1SOL  OW 1 0.106 0.837 -0.817 -1.300 
    20.0 20.0 20.0 
    moja woda t= 4 
    . 
    . 
    . 

我的腳本是:

!/usr/bin/perl -w 

use strict; 

my $list=$ARGV[0]; 


open(LST,$list) or die; 

my $time=0; 

my @id_table; 
my @nr_table; 

open(GRO,">waters.gro") or die; 

while(<LST>) { 
    my $pdb_file=$_; 
    chomp $pdb_file; 
    my $pdb_id=substr $pdb_file,0,4; 
    open(PDB,$pdb_file) or die; 
    while(<PDB>) { 
     my $line=$_; 
     my $x=substr $line,30,8; 
     my $y=substr $line,38,8; 
     my $z=substr $line,46,8; 
     my $en=substr $line,54,8; 
     my $w_id=substr $line,23,3; 
     print GRO "moja woda t= $time \n"; 
     printf(GRO "%5d\n",1); 
     printf(GRO " 1SOL  OW 1%8.3f%8.3f%8.3f%8.3f\n",$x/10.0,$y/10.0,$z/10.0,$en); 
     print GRO " 20.0 20.0 20.0\n"; 
     $id_table[$time]=$pdb_id; 
     $nr_table[$time]=$w_id; 
     $time++; 
    } 
    close PDB; 
} 
close GRO; 

我想只有這些線轉換能量值小於0(最後一列)。我應該怎麼做?

謝謝你在前進, M.

回答

0

,而不是試圖提取基於字符串中的特定位置的值,我會用split函數每一行分成數組。

替換此:

my $x=substr $line,30,8; 
my $y=substr $line,38,8; 
my $z=substr $line,46,8; 
my $en=substr $line,54,8; 
my $w_id=substr $line,23,3; 

與此:

my ($w_id, $x, $y, $z, $en) = (split(/\s+/, $line))[1, 5, 6, 7, 8]; 
next if $en >= 0; 

這應該是足以讓你想要的輸出。

它在做什麼?

my @array = split(/\s+/, $line)告訴perl將字符串拆分成一個列表。 /\s+/是一個正則表達式,它告訴split函數可以分解一個或多個空白字符。

@array將包含9個entires,每個數據列一個。由於您沒有使用所有列,因此我使用數組切片僅提取您感興趣的條目。例如my ($zero, $one, $three) = (@array)[0, 1, 3]提取@array索引0,1和3處的元素,並將它們放入變量$ zero,$一個,三個分別。

如果$en的值爲正數,next if $en > 0;行將通知腳本跳過循環的當前迭代的其餘部分。

+0

謝謝你的幫助! –

+0

沒問題!在你的新問題http://stackoverflow.com/questions/34799244/perl-sort-numbers-in-column-in-order它看起來像你用這個答案。如果你接受了你實際使用的答案,它會讓我開心。;-) –

+0

我接受:)起初,我不知道這是什麼厚厚的:)對不起! –

2

好的,對於初學者 - 不要使用substr這個,這很討厭。嘗試split

然後你可以'測試'字段值。這是一個削減例如:

#!/usr/bin/env perl 
use strict; 
use warnings; 

my @nr_table; 
my @id_table; 

while (<DATA>) { 

    my @fields = split; 
    my ($pdb_id, $w_id) = @fields[0,1]; 

    if ($fields[8] < 0) { 
     print "moja woda t= ",scalar @id_table, "\n"; 
     printf("%5d\n",1); 
     printf(" 1SOL  OW 1%8.3f%8.3f%8.3f%8.3f\n", map { $_/10.0 } @fields[5..7], $fields[8]); 
     print " 20.0 20.0 20.0\n"; 
    } 
    push (@id_table, $pdb_id); 
    push (@nr_table, $w_id); 
} 

__DATA__ 
ATOM 367 OH2 HOH 367  -2.010 7.370 -7.369 -6.52 
ATOM 491 OH2 HOH 491  0.990 8.370 -8.369 -2.24 
ATOM 652 OH2 HOH 652  5.490 -6.130 2.631 2.98 
ATOM 689 OH2 HOH 689  6.490 -15.130 8.631 -4.23 
ATOM 738 OH2 HOH 738  7.490 19.870 -8.369 3.38 
ATOM 793 OH2 HOH 793  8.990 -2.630 -22.869 -2.29 
ATOM 857 OH2 HOH 857  10.490 13.370 -5.869 -1.31 

注 - 默認情況下split作用於$_ - 當前行,並分割在「任何空白」。

如果需要,您可以在條件內移動push語句。

+0

謝謝你的幫助! –

+0

如何對$ en列中的數字進行排序?我應該通過地圖還是不通過創建一個臨時數組? –

+0

你可以,但這是一個稍微不同的問題 - 上面的這個解決方案只是在文件中逐行處理。爲了排序,你需要將整個事物讀入一個數組(數組)。可以,但我會建議值得另一個問題,而不是試圖在這裏解釋。 – Sobrique