2014-09-23 47 views
0

在我以前的問題(https://stackoverflow.com/a/25735444/3767980)中,在jaypal的幫助下,我能夠爲ambigous和unambigous案例格式化我的約束。讓我們考慮這裏的含糊不清,因爲它更難。用VCG *替換perl腳本中的VCG1或VCG2

我有限制,看起來像

G6N-D5C-?: (116.663, 177.052, 29.149) K87CD/E85CB/E94CB/H32CB/Q21CB 
L12N-T11C-?: (128.977, 175.109, 174.412) K158C/H60C/A152C/N127C/Y159C(notH60C) 
K14N-E13C-?: (117.377, 176.474, 29.823) I187CG1/V78CG2 
A75N-Q74C-?: (123.129, 177.253, 23.513) V131CG1/V135CG1/V78CG1 

,並受到以下perl腳本:

#!/usr/bin/perl 

use strict; 
use warnings; 
use autodie; 
# 

open my $fh, '<', $ARGV[0]; 

while (<$fh>) { 
    my @values = map { /.(\d+)(\w+)/; $1, $2 } split '/', (split)[-1]; 
    my ($resid, $name) = /^[^-]+-.(\d+)(\w+)-/; 
    print "assign (resid $resid and name $name) ("; 
    print join (" or ", 
     map { "resid $values[$_] and name $values[$_ + 1]" } 
     grep { not $_ % 2 } 0 .. $#values 
    ); 
    print ") 3.5 2.5 4.5 ! $_"; 
} 

與輸出:

assign (resid 5 and name C) (resid 87 and name CD or resid 85 and name CB or resid 94 and name CB or resid 32 and name CB or resid 21 and name CB) 3.5 2.5 8.5 ! G6N-D5C-?: (116.663, 177.052, 29.149) K87CD/E85CB/E94CB/H32CB/Q21CB 
assign (resid 11 and name C) (resid 158 and name C or resid 60 and name C or resid 152 and name C or resid 127 and name C or resid 159 and name C) 3.5 2.5 8.5 ! L12N-T11C-?: (128.977, 175.109, 174.412) K158C/H60C/A152C/N127C/Y159C(notH60C) 
assign (resid 13 and name C) (resid 187 and name CG1 or resid 78 and name CG2) 3.5 2.5 8.5 ! K14N-E13C-?: (117.377, 176.474, 29.823) I187CG1/V78CG2 
assign (resid 74 and name C) (resid 131 and name CG1 or resid 135 and name CG2 or resid 78 and name CG1) 3.5 2.5 8.5 ! A75N-Q74C-?: (123.129, 177.253, 23.513) V131CG1/V135CG1/V78CG1 

  • 我需要幫助的是包含以V後跟2或3位數字開頭的條目以及!後面的CG1CG2。例子是V78CG2或V135CG1。
  • 我需要剋制相應的條目來處理通配符。也就是說,我需要限制返回像:

assign (resid 5 and name C) (resid 87 and name CD or resid 85 and name CB or resid 94 and name CB or resid 32 and name CB or resid 21 and name CB) 3.5 2.5 8.5 ! G6N-D5C-?: (116.663, 177.052, 29.149) K87CD/E85CB/E94CB/H32CB/Q21CB 
assign (resid 11 and name C) (resid 158 and name C or resid 60 and name C or resid 152 and name C or resid 127 and name C or resid 159 and name C) 3.5 2.5 8.5 ! L12N-T11C-?: (128.977, 175.109, 174.412) K158C/H60C/A152C/N127C/Y159C(notH60C) 
assign (resid 13 and name C) (resid 187 and name CG1 or resid 78 and name CG*) 3.5 2.5 8.5 ! K14N-E13C-?: (117.377, 176.474, 29.823) I187CG1/V78CG2 
assign (resid 74 and name C) (resid 131 and name CG* or resid 135 and name CG* or resid 78 and name CG*) 3.5 2.5 8.5 ! A75N-Q74C-?: (123.129, 177.253, 23.513) V131CG1/V135CG1/V78CG1 

我需要建議選擇匹配的行,然後再進行塗敷transfomation到集羣輸入(!之前)。我可以找到符合V.*CG[1-2]的基本正則表達式的行。

我想要一個在上面的perl腳本中的解決方案。

如果有什麼不清楚的地方,請發表評論。我還是比較新的。我提前感謝您的建議。

+0

你瞭解腳本你在工作?如果沒有,我會建議你試着找出解釋或者要求解釋,然後修改腳本以適當地處理這些行。 – 2014-09-23 07:09:19

+0

我明白它是如何工作的除了地圖的一切。我能夠爲模棱兩可的情況生成類似的腳本。我在地圖邏輯上遇到了麻煩,但我一直在閱讀它。我真的只需要幫助,彌補選擇線路和匹配相應的V CG限制之間的差距。我認爲最後做這件事最容易。我非常自信,我可以在bash中做到這一點,但我希望只使用一個腳本。我可以使用bash解決方案來補充我的問題。 – PhysicalChemist 2014-09-23 07:21:29

+0

哪個「地圖」行?第一個,用正則表達式呢? – 2014-09-23 08:12:48

回答

1

以下是腳本的修改版本,並解釋了發生了什麼。該my @values = map { ... } split '/', (split)[-1];是有點棘手明白,所以我會認爲分開解釋:

map以一個數組,並適用無論是大括號到陣列中的每個成員內,輸出新的數組。兩個split s用於切斷線路。如果沒有任何參數使用,split需要$_作爲輸入並分割空白。因此,第一split需要$_,這是當前行,並且由空間分割它:

input: 
'G6N-D5C-?: (116.663, 177.052, 29.149) K87CD/E85CB/E94CB/H32CB/Q21CB' 

the array created by calling split: 
'G6N-D5C-?:', '(116.663,', '177.052,', '29.149)', 'K87CD/E85CB/E94CB/H32CB/Q21CB' 

第二split豬排上向上的/輸入;作爲輸入,它使用由第一個split創建的數組中的最後一項 - 即(split)是「通過在空格中拆分$_創建的數組」的簡寫,而(split)[-1]是該數組的最後一個元素。

input: 
K87CD/E85CB/E94CB/H32CB/Q21CB 

array created by calling `split "/"` 
'K87CD', 'E85CB', 'E94CB', 'H32CB', 'Q21CB' 

map命令然後施加一個正則表達式來這個陣列的每個成員:

/.(\d+)(\w+)/; # match any character (.) followed by one or more digits (\d) 
       # followed by one or more alphanumeric (\w) characters. 

托架捕獲結果到只讀變量$1$2。地圖中的第二條語句將這些字符添加到由map命令創建的陣列中。默認情況下,PERL把結果的最後一條語句的入陣,所以你可以做這樣的事情:

my @arr = (1, 2, 3, 4); 
my @two_times = map { $_ * 2 } @arr; 
# @two_times is (2, 4, 6, 8) 

(該模式匹配的「結果」實際上是1 $和$ 2,這樣的聲明$1, $2到它們添加到@values陣列不是嚴格必需的。)

所以@values = map { /.(\d+)(\w+)/; $1, $2 } @array捕獲來自每個元件比賽中@array並將它們放在@values

我希望腳本的其餘部分是可以理解的;如果不是,我建議拆分每個命令並使用Data::Dumper來檢查結果,以便確定發生了什麼。

要改變腳本以不同的方式處理VnnCG1/VnnCG2條目,我在map命令中添加了一行,查找與該模式匹配的任何殘基,並用VnnCG*替換它。然後,我修改了匹配的正則表達式,以便抓取剩餘名稱的相應部分,但不會抓取不適當的數據(例如(notB28DG))。下面是評論新的腳本:

#!/usr/bin/perl 
use strict; 
use warnings; 
use feature ':5.10'; 
use autodie; 

open my $fh, '<', $ARGV[0]; 

while (<$fh>) { 

    # a brief guide to regexps: 
    # \d  = digits 
    # \w  = digits or letters or _ 
    # [ ] = match any of the characters within these brackets 
    # () = capture the value in these brackets, save it to $1, $2, $3, etc. 
    #  (brackets are also used for alternation, but not in this case) 
    # *  = match 0 or 1 times 
    # +  = match 1 or more times 
    # \*  = match the character * 
    # s/// = search and replace 
    # /x  = ignore whitespace 

    my @values = map { 
     # find the pattern 
     s/V  # V 
     (\d+) # one or more digits; the brackets mean we capture the value 
       # and it gets saved in $1 
     CG  # CG 
     [12] # either 1 or 2 
     /V$1CG*/x; #replace with V $1 CG * 

     # find the pattern 
     /.  # any character 
     (\d+) # one or more digits; capture the value in $1 
     ([A-Z][\w\*]*) # a letter followed by zero or more alphanum or * 
     /x;   # the value is captured in $2 

     # put $1 and $2 into the array we're building 
     $1, $2 
     } split '/', (split)[-1]; 

    my ($resid, $name) = /^[^-]+-.(\d+)(\w+)-/; 
    # compose the new string 
    my $str = "assign (resid $resid and name $name) (" 
    . join (" or ", 
     map { "resid $values[$_] and name $values[$_ + 1]" } 
     grep { not $_ % 2 } 0 .. $#values 
    ) 
    . ") 3.5 2.5 8.5 ! $_"; 
    # "say" prints out the string to STDERR and automatically adds a carriage return 
    say $str; 
} 

短版的「核心」的腳本沒有評論:

foreach (@data) { 
    my @values = map { 
     s/V(\d+)CG[12]/V$1CG*/; /.(\d+)([A-Z][\w\*]*)/; 
     } split '/', (split)[-1]; 
    my ($resid, $name) = /^[^-]+-.(\d+)(\w+)-/; 
    say "assign (resid $resid and name $name) (" 
    . join (" or ", 
     map { "resid $values[$_] and name $values[$_ + 1]" } 
     grep { not $_ % 2 } 0 .. $#values 
    ) 
    . ") 3.5 2.5 8.5 ! $_"; 
} 
+0

非常感謝您花時間提供如此豐富的答案。 – PhysicalChemist 2014-09-23 12:56:30

+1

:)我希望它也能幫助你解決將來的編程問題! – 2014-09-23 13:11:02

+1

再次感謝,因爲你的偉大答案,我今天能夠獨自完成其他類型的約束(即使它確實需要大部分時間,哈哈).. :) – PhysicalChemist 2014-09-24 03:42:44