0

bioinfo2.pl の 24 行目の ");" 付近に構文エラーがあります。bioinfo2.pl の 26 行目、"}" 付近の構文エラー bioinfo2.pl の実行は、コンパイル エラーにより中止されました。

print "Enter file name......\n\n";
chomp($samplefile = <STDIN>);
open(INFILE,"$samplefile") or die "Could not open $samplefile";

@residue_name= ();
@residue_count= ();
while($newline = <INFILE>) 
{
    if ($newline =~ /^ATOM/)
    {
        chomp $newline;
        @columns = split //, $newline;  
        $res = join '', $columns[17], $columns[18], $columns[19];
        splice @columns,0;
        $flag=0
        for ($i = 0; $i<scalar(@residue_name); $i++;) 
        {
            if (@residue_name[i] == $res)
            {
                @residue_count[i] = @residue_count[i] + 1;
                $flag=1;

            }
        }
        if($flag==0)
        {
            push(@residue_name, $res);  
        }

        for ($i = 0; $i<scalar(@residue_name); $i++) 
        {   
            print (@residue_name[i], "-------", @residue_count[i], "\n");
        }
    }   
}               
4

2 に答える 2

2

さまざまなエラーをすべて突き止めるのにしばらく時間がかかりました。他の人が言ったように、使用use warnings;してuse strict;

ルール #1 :完全に適切な行を指す構文エラーが表示される場合は常に、前の行にセミコロンがないかどうかを常に確認する必要があります。の後のセミコロンを忘れました$flag=0

すべての問題を追跡するために、コードをより現代的な構文に書き直しました。

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

print "Enter file name......\n\n";
chomp (my $samplefile = <STDIN>);
open my $input_file, '<:crlf', $samplefile;

my @residue_name;
my @residue_count;
while ( my $newline = <$input_file> ) {
    chomp $newline;
    next if $newline !~ /^ATOM/;  #Eliminates the internal `if`
    my @columns = split //, $newline;
    my $res = join '', $columns[17], $columns[18], $columns[19];
    my $flag = 0;
    for my $i (0..$#residue_name) {
        if ( $residue_name[$i] == $res ) {
            $residue_count[$i]++;
            $flag = 1;
        }
    }
    if ( $flag == 0 ) {
        push @residue_name, $res;
    }

    for my $i (0..$#residue_name) {
        print "$residue_name[$i] -------  $residue_count[$i]\n";
    }
}
close $input_file;

変更点のリストは次のとおりです。

  • 2 行目と 3 行目: 常に and を使用use strict;use warnings;ます。これらは、プログラム エラーの約 90% を追跡するのに役立ちます。
  • 4 行目: を使用しuse autodie;ます。これにより、ファイルが開いているかどうかを確認する必要がなくなります。
  • 行 7 (およびその他) : 使用use strict;するには、変数を事前に宣言する必要があります。したがって、my変数が最初に使用されるたびに表示されます。
  • 行 8 : 3 つのパラメーターopenを使用し、グロブの代わりにファイル ハンドルにローカル変数を使用します (つまり、$file_handle と FILE_HANDLE の比較)。主な理由は、ローカル変数はグロブよりもサブルーチンに渡すのが簡単だからです。
  • 9 行目と 10 行目: 配列を初期化する必要はありません。配列を宣言するだけで十分です。
  • Line 13 :chomp読み込んだらすぐに。
  • 行 14 : これを行うと、ループif全体を包含する内部ステートメント全体が削除されます。whileコード ブロック ( ifwhile、 などfor) が長くなりすぎたり、相互に埋め込まれすぎたりすると、把握するのが難しくなります。このnextように使えば、ifブロックをなくすことができます。
  • 行 17 : ここで、最初の構文エラーの原因となったセミコロンを見逃しました。主なことは、非常に紛らわしいspliceコマンドを削除したことです。配列をゼロにしたい場合は、@columns = ();どちらがより明確であるかを簡単に言うことができます。ただし、ループ@columns内でのみスコープ内にあるwhileため、ファイルの行ごとに再定義されるため、空白にする必要がなくなりました。
  • 行 18 : これは、配列のすべての行をループする、よりクリーンな方法です。スカラー @resudue_name が要素の数を与えている間$#residue_name、あなたに最後のインデックスを与えることに注意してください。$#residue_nameこれは非常に重要な違いです。@array=がある場合は4 に(0, 1, 2, 3, 4)なりますが、5 になります。スタイル for ループを使用すると、これを行うときに少し混乱する可能性があります。またはを使用する必要がありますか?nameを使用することは明らかであり、C スタイルステートメント内に余分なセミコロンを含むエラーの可能性を排除します。エラーの可能性と構文の複雑さのため、Python を作成した開発者は、C スタイルの for ループを許可しないことにしました。$#arrayscalar @arrayC>>=(0..$#residue)for
  • 行 19 (およびその他) : 使用すると、いくつかの問題があったwarningsことが指摘されました。@residue_name[i]まず第一に$residue_name[...]、配列にインデックスを付けるときに使用する必要があり、第二に、iは整数ではありません。あなたが意味し$iた。したがって、@residue_name[i]になり$residue_name[$i]ます。
  • 20 行目: 変数をインクリメントする場合は、$foo++;or$foo += 1;と notを使用します$foo = $foo + 1;。最初の 2 つは、変数をインクリメントしていて、その値を再計算していないことを簡単に確認できるようにします。
  • 行 29 : Perl の優れた機能の 1 つは、変数を引用符内で補間できることです。すべてを 1 組の引用符で囲むことができます。ところで、ステートメントを複数の部分に分割する場合は.、and notを使用する必要があります。はリスト操作です。これは、出力するものが の値に依存することを意味します。は、リストを文字列に補間するときに、リストの各項目の間に何を出力するかを指定する Perl 変数です。,print,$,$,

これをあなたのコーディング能力に対する批判と見なさないでください。Perl を教える多くの Perl 本、および Perl を教える多くのコースは、Perl 3.0 の時代に戻ったように Perl を教えているようです。私が最初に Perl を学んだのは Perl 3.0 のときで、私の構文の多くはあなたのものに似ていたでしょう。しかし、Perl 5.x はかなり前からリリースされており、プログラミングをより簡単に、より読みやすくする多くの機能が含まれています。

Perl 3.0 の習慣から抜け出し、Perl 4.0 およびそれ以降の Perl 5.0 の習慣に移行するには、しばらく時間がかかりました。他の人が何をしているかを見て、Stack Overflow のようなフォーラムで質問することで学びます。

あなたのコードがうまくいくとはまだ言えません。私はあなたの意見を持っていないので、それに対してテストすることはできません. ただし、このコードをプログラムの基礎として使用すると、これらのエラーのデバッグが非常に簡単になります。

于 2013-02-18T18:41:51.213 に答える
2

することをお勧めしuse strict; use warningsます。これにより、変数を宣言する必要があり ( で行うことができますmy)、多くの可能性のあるエラーを排除します。

ここに私が気づいたいくつかのことがあります:

  1. sayPerl5 v10 以降では、関数 (use 5.010または)を使用できますuse feature 'say'。これは同様printに機能しますが、最後に改行を追加します。

  2. open の引数が 2 つの形式は使用しないでください。これにより、いくつかのセキュリティの問題が発生します。明示的なオープン モードを提供します。また、スカラーをファイルハンドルとして使用できます。これにより、ファイルの自動クローズなどの優れた機能が提供されます。

    open my $INFILE, '<', $samplefile or die "Can't open $samplefile: $!";
    

    変数には、失敗し$!た理由が含まれています。open

  3. 配列から要素のリストを取得する場合は、スライス (複数の添え字) を使用できます。

    my $res = join '', @columns[17 .. 19]; # also, range operator ".."
    

    @複数の要素を使用するため、シジルが になっていることに注意してください。

  4. これsplice @columns, 0は、「配列からすべての要素を削除し、それらを返す」という凝った言い方です。これは必須ではありません (後でその変数から読み取る必要はありません)。レキシカル変数 ( で宣言my) を使用すると、ループの反復ごとwhileに新しい変数を受け取ります。本当に内容を削除したい場合は、undef @columns. これはより効率的なはずです。

  5. 実際のエラー:$flag = 0ループを開始する前にステートメントを終了するには、後にセミコロンが必要です。

  6. 実際のエラー: C スタイルの for ループには、括弧で囲まれた 3 つの式が含まれています。最後のセミコロンはそれらを 4 つの式に分割します。これはエラーです。単純に削除するか、次のヒントをご覧ください。

  7. C スタイルのループ ( for (foo; bar; baz) {}) は面倒で、エラーが発生しやすくなります。範囲(インデックスなど)のみを反復する場合は、範囲演算子を使用できます。

    for my $i (0 .. $#residue_name) { ... }
    

    シジルは、配列の$#最後のインデックスを示します。

  8. 配列に添え字を付ける (配列要素にアクセスする) 場合は、インデックスの印を含める必要があります。

    $residue_name[$i]
    

    $1 つの要素のみにアクセスするため、配列の記号は であることに注意してください。

  9. パターン$var = $var + 1は に短縮できます$var++。これはインクリメント演算子を使用します。

  10. ゼロを除くすべての数値が真と見なされる$flag == 0ため、 は と省略できます。!$flag

これはスクリプトの再実装です。ファイル名をコマンド ライン引数として受け取ります。これは、ユーザーにプロンプ​​トを表示するよりも柔軟です。

#!/usr/bin/perl

use strict; use warnings; use 5.010;

my $filename = $ARGV[0]; # @ARGV holds the command line args
open my $fh, "<", $filename or die "Can't open $filename: $!";

my @residue_name;
my @residue_count;

while(<$fh>) { # read into "$_" special variable
   next unless /^ATOM/; # start a new iteration if regex doesn't match

   my $number = join "", (split //)[17 .. 19]; # who needs temp variables?

   my $push_number = 1; # self-documenting variable names
   for my $i (0 .. $#residue_name) {
       if ($residue_name[$i] == $number) {
           $residue_count[$i]++;
           $push_number = 0;
       }
   }
   push @residue_name, $number if $push_number;

   # are you sure you want to print this after every input line?
   # I'd rather put this outside the loop.
   for my $i (0 .. $#residue_name) {
       say $residue_name[$i], ("-" x 7), $residue_count[$i]; # "x" repetition operator
   }
} 

そして、大きな入力ファイルに対してより高速な実装を次に示します。配列をループする代わりに、ハッシュ (ルックアップ テーブル) を使用します。

#!/usr/bin/perl

use strict; use warnings; use 5.010;

my $filename = $ARGV[0]; # @ARGV holds the command line args
open my $fh, "<", $filename or die "Can't open $filename: $!";

my %count_residue; # this hash maps the numbers to counts
                   # automatically guarantees that every number has one count only

while(<$fh>) { # read into "$_" special variable
   next unless /^ATOM/; # start a new iteration if regex doesn't match

   my $number = join "", (split //)[17 .. 19]; # who needs temp variables?

   if (exists $count_residue{$number}) {
     # if we already have an entry for that number, we increment:
     $count_residue{$number}++;
   } else {
     # We add the entry, and initialize to zero
     $count_residue{$number} = 0;
   }
   # The above if/else initializes new numbers (seen once) to zero.
   # If you want to count starting with one, replace the whole if/else by
   #     $count_residue{$number}++;

   # print out all registered residues in numerically ascending order.
   # If you want to sort them by their count, descending, then use
   #     sort { $count_residue{$b} <=> $count_residue{$a} } ...
   for my $num (sort {$a <=> $b} keys %count_residue) {
       say $num, ("-" x 7), $count_residue{$num};
   }
} 
于 2013-02-18T17:33:29.573 に答える