2014-01-28 169 views
-1

我是新來的perl,我想複製我用awk編寫的代碼到perl。 我想複製一個特定的行數,這取決於在位置上匹配的字符串。Perl:for循環/字符串操作

樣品輸入文件:

Dummy lines Ix Dummy lines 
Dummy lines Ix Dummy lines 
text Ix A(Ay) test text 
Dummy lines Ix Dummy lines 
Dummy lines Ix Dummy lines 

在閱讀此輸入文件我會爲您在第二位置「九」字符串,重複的次數。 (如圖中的示例輸出3次)

樣本輸出文件

Dummy lines Ix Dummy lines 
Dummy lines Ix Dummy lines 
text I1 A(A3) test text 
text I2 A(A2) test text 
text I3 A(A1) test text 
Dummy lines Ix Dummy lines 
Dummy lines Ix Dummy lines 

任何幫助將appriciated。

問候


我失敗的代碼是:

#!/usr/bin/perl -w 
use strict; 
my $loop=0; 
my $max=3; 
my $in_file="$ARGV[0]"; 

open (PH, "$in_file") or die "check file"; 
while (<PH>) { 
chomp; 
if ($_ =~ /Ix/) { 
    $loop=0; 
    while ($loop < $max) { 
     my $local = $max-$loop; 
     $_ =~ s/Ix/I$loop/; 
     $_ =~ s/Ay/A$local/; 
     print "$_\n"; 
     $loop++; 
     } 
    } else { 
     print "$_\n"; 
    } 
} 
close(PH); 

我要找的財產以後像 「$ 2〜/ IX /」 在awk中,我可以在我的,如果條件的地方。我不確定perl是否允許你這樣做。除此之外,我無法在本身使用當前$ loop的值。

+0

有很多方法可以編寫這段代碼。請給我們一個真實的用例。 – bluefeet

+0

是與所示完全相同的文字輸入? 「Ix」,「Ay」?是否有任何y和x被替換,或者只有第二個字段中的I和第三個字段中的y(或多個y?)之後的x? – ysth

回答

2

你最大的問題是你編輯$_,所以第二次通過循環,字符串中不再有「Ix」和「Ay」。

$loop=0; 
while ($loop < $max) { 
    my $local = $max-$loop; 
    my $line = $_; 
    $line =~ s/Ix/I$loop/; 
    $line =~ s/Ay/A$local/; 
    print "$line\n"; 
    $loop++; 
} 

你也可以考慮使用for循環:

for my $loop (0 .. ($max - 1)) { 
     my $local = ($max - $loop); 
     my $line = $_; 
     $line =~ s/Ix/I$loop/; 
     $line =~ s/Ay/A$local/; 
     print "$line\n"; 
    } 

如果這些是空間分隔的「列」,你想只有在「列」編輯值2和3(您在awk$2提及似乎暗示),您可以拆分輸入,以及是否:split命令故意模仿awk

perldoc -f split

 As another special case, "split" emulates the default behavior of 
     the command line tool awk when the PATTERN is either omitted or a 
     literal string composed of a single space character (such as ' ' 
     or "\x20", but not e.g. "/ /"). In this case, any leading 
     whitespace in EXPR is removed before splitting occurs, and the 
     PATTERN is instead treated as if it were "/\s+/"; in particular, 
     this means that any contiguous whitespace (not just a single space 
     character) is used as a separator. However, this special treatment 
     can be avoided by specifying the pattern "/ /" instead of the 
     string " ", thereby allowing only a single space character to be a 
     separator. 

     If omitted, PATTERN defaults to a single space, " ", triggering 
     the previously described awk emulation. 

這給我們帶來:

local $" = ' ';                     #" (syntax highlighting bug on SO) 

my @input = split; 
if ($input[1] =~ /Ix/) { 
    for my $loop (0 .. ($max - 1)) { 
     my $local = ($max - $loop); 
     my @line = @input; 
     $line[1] =~ s/Ix/I$loop/; 
     $line[2] =~ s/Ay/A$local/; 
     print "@line\n"; 
    } 
} else { 
    print "$_\n"; 
} 

特殊變量$"具體是指"@line"將在印有該陣列的每個元素之間的' ',讓您得到您的「列」回輸出。

最後一個暗示:你die可以僅通過包括$!打印有意義的錯誤消息:

#!/usr/bin/perl -w 
use strict; 
my $loop=0; 
my $max=3; 
my $in_file="$ARGV[0]"; 

local $" = ' ';                     #" (syntax highlighting bug on SO) 

open (PH, "$in_file") or die "check file: $!"; 
while (<PH>) { 
    chomp; 
    my @input = split; 
    if ($input[1] =~ /Ix/) { 
     for my $loop (0 .. ($max - 1)) { 
      my $local = ($max - $loop); 
      my @line = @input; 
      $line[1] =~ s/Ix/I$loop/; 
      $line[2] =~ s/Ay/A$local/; 
      print "@line\n"; 
     } 
    } else { 
     print "$_\n"; 
    } 
} 
close(PH); 

編輯:

由於@Kenosis在評論中指出,你所提供的樣本輸出有I計數器運行1 ... 3而不是0 ... 2。在你的循環中,你將計數器初始化爲0,並且只在打印後才遞增,所以我將(錯誤)解釋爲你的意圖。

幸運的是,改變這個很簡單:

for my $loop (1 .. $max) { 
     my $local = (1+ $max - $loop); 
     … 

由於還指出,使用的詞彙(my)變量的文件句柄是通常更安全/更好地爲各種技術原因,以及;

open my $ph, '<', $infile or die "Can't read $infile: $!"; 

    … 

    while (<$ph>) { 
    … 

...儘管您使用的舊式文件句柄(裸詞標識符)仍然有效。 這也顯示了「3參數open」,它在「2-arg」形式中防止了一些可能的安全漏洞(或奇怪的,令人撓頭的瘋狂行爲),<預設爲文件名。

而且,作爲@Kenosis筆記,$"確實發生默認爲' ',但我傾向於重新定義「以防萬一」(我個人有一個Perl代碼很多重新定義它象外之象','"\t"由於種種原因,你可以local LY重置,以確保您的輸出將是什麼樣子)

+0

事實上,這產生了「文本I0 ..文本I2」。 Perl的'''''''默認設置爲''''。對於文件句柄,最好使用詞法變量而不是空白詞。 – Kenosis

+0

啊,我模仿我認爲他想從代碼中得到的行爲,現在我看到了這個例子輸出實際上有1 ... 3,而不是0 ... 2,同意詞彙,但試圖類似於原始代碼,所以他可以遵循;'$「'只是安全/偏執狂。不過,我會編輯增量來匹配。 – BRFennPocock

+0

所有優點!知道'I0 ..'是次要的。對OP很好的幫助。 – Kenosis

0

這裏的另一種選擇:

use strict; 
use warnings; 

while (<>) { 
    if (/^\S+?\s+Ix\s+/) { 
     my (%h, $c) = (I => 1, A => -3); 
     $_ = join '', 
      map { s/\b(I)x|(A)y\b/$c = $1 ? $1 : $2; $c . abs $h{$c}++/ge; $_ } 
      my @lines = ($_) x 3; 
    } 

    print; 
} 

用法:perl script.pl inFile [>outFIle]

最後一個可選參數將輸出指向文件。

輸出你的數據集:

Dummy lines Ix Dummy lines 
Dummy lines Ix Dummy lines 
text I1 A(A3) test text 
text I2 A(A2) test text 
text I3 A(A1) test text 
Dummy lines Ix Dummy lines 
Dummy lines Ix Dummy lines 

希望這有助於!