2017-05-07 22 views
1

Ich versuche, eine Sequenz beginnend mit ATG und stoppen mit TAG, TAA oder TGA aus einer Textdatei.In Perl, warum bekomme ich "nicht initialisierten Wert in Mustervergleich (m //)", wenn ich versuche, zu überprüfen, ob eine Variable zwei Muster entspricht?

Ich erhalte die Fehlermeldung

Verwendung von nicht initialisierten Wert $ _ in Mustererkennung (m //) in Zeile 12

und es zählt jede Zeile nicht nur die, die ich will.

Ich denke, es ist etwas falsch, wie ich die regulären Ausdrücke verwende, aber ich weiß nicht wie.

use strict; 
use warnings; 

my $test = "Bin.txt"; 
my $count = "0"; 

sub ORF { 
    my ($file) = @_; # reading file in 

    open (my $FH, "<", $file) or die "Can't open $file: $!"; 

    while (my $line = <$FH>) { #reading each line of file 

     if ($line = ((~/^ATG/) and (~/TAG$|TAA$|TGA$/))) { # looking for sequence with ATG at the beginning and TAG,TAA,TGA at the end 
      $count = $count +1; # counting these sequences 
     } 
    } 
} 

ORF $test; 
print $count; 

Antwort

2

Die Wirkung von

$line = ((~/^ATG/) and (~/TAG$|TAA$|TGA$/)) 

ist das Ergebnis der

(~($_ =~ /^ATG/) and ~($_ =~ /TAG$|TAA$|TGA$/)) 

zu $line zuzuweisen.

=~ ist ein einzelner Bediener. = und ~ bedeuten für sich verschiedene Dinge. =~ kann nicht so aufgeteilt werden.

Was müssen Sie schreiben ist:

($line =~/^ATG/) and ($line =~ /TAG$|TAA$|TGA$/) 

Ich empfehle Ihnen, tatsächlich halten die zwei einfache Regex passt entsprechend „$line beginnt mit ATG und endet mit einem TAG, TAA oder TGA“ statt versuchen, beide Bedingungen in einem einzigen Muster zu kombinieren und es weniger lesbar zu machen.

Weitere Hinweise:

  • Schreiben Sie nicht my $count = "0";. Dies ist eigentlich eine FAQ: What is wrong with always quoting "$vars": "Das Problem ist, dass diese doppelten Anführungszeichen Stringifizierung zwingen - Zahlen und Referenzen in Strings - auch wenn Sie nicht möchten, dass sie Zeichenfolgen sein." In diesem Fall sollten Sie initialisieren Sie es mit 0.

  • Anstelle von $count = $count +1++ $count verwenden.

  • Geben Sie anstelle eines globalen $count den Zählerstand aus dem Unterprogramm zurück.

  • Obwohl lexikalische Dateihandles beim Verlassen des Bereichs automatisch geschlossen werden, ist es dennoch besser, sie explizit zu schließen, wenn sie nicht mehr benötigt werden.

  • Lassen Sie keine Klammern aus Unterprogrammaufrufen aus. Das heißt, anstelle von ORF $test schreiben Sie immer ORF($test), insbesondere, da alle Bareword-Namen in Großbuchstaben für Datei-Handle oder Konstanten auf Paketebene reserviert sind.

Also, ich würde Ihr Code als neu schreiben (nicht getestet, weil ich nicht die Daten haben):

use strict; 
use warnings; 

run(@ARGV); 

sub run { 
    my $file = shift; 
    print ORF($file), "\n"; 
    return; 
} 

sub ORF { 
    my $file = shift; 
    open my $fh, '<', $file 
     or die "Can't open '$file': $!"; 

    my $count = 0; 
    while (my $line = <$fh>) { 
     if (($line =~ /^ATG/) and ($line ~= /(?:TAG|TAA|TGA)$/)) { 
      ++ $count; 
     } 
    } 
    close $fh 
     or die "Failed to close '$file': $!"; 

    return $count; 
} 
+0

Dank! Das war sehr hilfreich (und macht sehr viel Sinn). –

+1

* 'Was falsch daran ist, immer' $ vars '' * zu zitieren, geht darum, doppelte Anführungszeichen um Variablen zu setzen, nicht um numerische Konstanten, was eine viel geringere Sünde ist. Und danke, dass Sie den passenden Pre-Increment-Operator anstelle des allgegenwärtigen Post-Increments verwenden – Borodin

1

Sie mißbrauchen die ~ Operator. Es ist eine bitweise Negation und hat nichts mit Regexes zu tun. Die, die Sie wahrscheinlich gemeint haben, ist =~, aber es kann nicht geteilt werden. Deshalb sollte der Konditionaloperator aussehen

if ($line =~ /^ATG/ and $line =~ /TAG$|TAA$|TGA$/) 

Aber dies kann in einem einzigen regulären Ausdruck beschrieben werden:

if ($line =~ /^ATG.*(?:TAG|TAA|TGA)$/)) 
Verwandte Themen