1. Diese Seite verwendet Cookies. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies. Weitere Informationen

bestimmtes Wort aus Array extrahieren

Dieses Thema im Forum "CGI, Perl, Python, Ruby, Power Shell" wurde erstellt von Pauline25, 5. August 2011.

  1. Pauline25

    Pauline25 Grünschnabel

    Hallo zusammen. Habe gerade damit begonnen mir Perl bei zu bringen und stecke jetzt in einem Skript fest. Ich möchte Daten aus einer Textdatei splitten und aus dem mit den substrings befüllten Array ein ganz bestimmtes Wort rausholen. Das Splitten funktioniert (hab ich seperat getestet). Dass Wort, das ich suche ist im 8. substring, heißt "GeneID" und liegt immer zwischen anderen Werten. Also wie gesagt, bis zum splitten funktionierte es noch, aber jetzt muss irgendwo ein Fehler drin sein:

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


    my $in;
    my $data;
    my @array;
    my $key;
    my $slice;
    my $array;



    open $in, '<', "Genomteil.gff" or die $!;
    while ($data = <$in>) {
    chomp $data;
    @array = split(/\t/, $data);
    $slice = ($array [8] => ~/\bGeneID\b/i);
    }
    print $slice;

    close $in;

    Würd mich freuen, wenn jemand einen Tipp hätte.

    LG
  2. renee

    renee Erfahrenes Mitglied

    Wenn es die 8. Spalte ist, dann musst Du $array[7] schreiben, weil die Arrayelemente bei 0 anfangen:

    Code (Text):
    1.  
    2. @array = (
    3.     'element1',       # $array[0]
    4.     'element2',       # $array[1] ...
    5.  
  3. Pauline25

    Pauline25 Grünschnabel

    Sorry, war nicht so ganz klar ausgedrückt. Das Wort ist definitiv im $array [8], dass die Elemente bei 0 anfangen, hatte ich bedacht. Ich dachte der Fehler liegt in der Angabe ~/\bGeneID\b/i.

    Hat jemand ne Idee?
  4. deepthroat

    deepthroat Premium-User

    Hi.

    Dir ist aber schon bewußt, das du den Wert von $slice nur einmal nach der Schleife ausgibst, also erst wenn die ganze Datei verarbeitet wurde?

    Was möchtest du denn mit dieser Zeile bezwecken? Möchtest du evtl. einfach $array[8] an \bGeneID\b splitten?

    Verwende bitte die Code-Tags! Und mach doch einfach mal ein konkretes Beispiel, mit Eingabedatei und was du dann gerne als Ausgabe haben würdest...

    Gruß
  5. renee

    renee Erfahrenes Mitglied

    Bei so etwas wäre es dann gut, wenn Du eine Ausgangsdatei postest und beschreibst, was Du am Ende haben willst (das könntest Du jetzt ja noch nachholen).

    Das mit dem Index, der bei 0 anfängt, ist ein beliebter Fehler bei Einsteigern.

    Ansonsten fällt mir die Zeile

    Code (Text):
    1. $slice = ($array [8] => ~/\bGeneID\b/i);
    auf.

    Du meinst wohl eher das hier:

    Code (Text):
    1. $slice = $array[8] if $array[8] =~ /\bGeneID\b/i;
  6. Pauline25

    Pauline25 Grünschnabel

    Danke schon mal für die Antworten und auf euren Rat noch mal ganz von vorne.

    Die Zeilen meine Ausgangsdatei siehen so aus:
    Zeile 1: NC_014171.1 RefSeq gene 9197 10736 . + . ID=NC_014171.1:rrf_1;locus_tag=BMB171_C5089;db_xref=GeneID:9191048
    Zeile 2: NC_014171.1 RefSeq gene 1802 2947 . + . ID=NC_014171.1:dnaN1;locus_tag=BMB171_C0002;db_xref=GeneID:9191043

    Aus dieser Datei möchte ich jeweils die Zeichenkette "GeneID:91910XY" extrahieren (mit diesem Wert möchte ich später weiterarbeiten, dass ist aber jetzt egal-das möchte ich zunächst selbst versuchen. Also vergesst ruhig, dass ich mit meinem Skript nur den letzten Wert nach Ende der Schleife ausgeben kann!)

    Mein aktuelles Skript sieht jetzt so aus:

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

    my $in;
    my $data;
    my @array;
    my $key;
    my $slice;
    my $array;
    my @geneID;




    open $in, '<', "Genomteil.gff" or die $!;
    while ($data = <$in>) {
    chomp $data;
    @array = split(/\t/, $data);


    if (my $array = ~ /[\d,\w,\s,]* "; db_xref=GeneID: [d*]\n/) {

    print '$1';
    }

    };



    close $in;


    Im Prinzip möchte ich sagen: wenn du folgendes findest: xy Anzahl von Buchstaben, Zeichen, Zahlen und danach den Marker: ; db_xref=GeneID:, dann extrahiere mir die darauf folgende Zahlenfolge!

    Okay, ich hoffe damit kann jetzt einer was anfangen. Danke euch.

    LG
  7. deepthroat

    deepthroat Premium-User

    [perl]my $db_xref = $1 if ($array[8] =~ /(GeneID:\d+));[/perl]
    Bitte benutze die Code-Tags! Schreibe einfach [perl] ... [/perl] um deinen Code. Dann bleiben auch die Einrückungen erhalten.
    Es ist unsinnig in einer Zeichenklasse Zeichen zu wiederholen. Und was ist "[d*]"? Meintest du evtl. \d+? Und das \n ist nach einem chomp nicht mehr in deinem String enthalten, so dass der reg. Ausdruck nie mit dem Text übereinstimmen dürfte

    Gruß
  8. Pauline25

    Pauline25 Grünschnabel

    okay, dass war einiges, was ich überarbeiten muss. ich werd es mal umbauen.

    vielen lieben dank!

    gruß
  9. Pauline25

    Pauline25 Grünschnabel

    Okay, soweit ist es umgebaut - leider funtioniert es immer noch nicht, wie es soll.

    Ich habe die konkrete Vorgabe etwas wie das hier zu programmieren:

    [perl] my $GeneID = $1 if ($array [8] = ~ /\w+\W+;db_xref=GeneID:(\d+)\n/) [/perl]

    # w+/W+ :in $array [8] kommt zunächst eine unbestimmt lange Folge von Buchstaben, Zeichen und Zahlen
    # ;db_xref=GeneID: dann kommt der immer gleiche Marker, der immer vor der zu extrahierenden Zahlenfolge steht
    #(\d+) hier ist die Zahlenfolge, die ich extrahieren will
    # abschließend folgt ein Zeilenumbruch

    chomp hab ich rausgenommen, ich vermute dass irgendwas mit der syntax nicht stimmt, finde aber nirgends Beispiele, bei denen nach so genauen Vorgaben extrahiert wird.

    LG
  10. deepthroat

    deepthroat Premium-User

    Ich sehe jetzt nicht wo der Fehler liegt. Ich kann es aber auch nicht ausprobieren. Häng doch mal eine (minimale) Beispieldatei an und poste deinen konkreten Code so wie er jetzt aussieht.

    Und es sieht so aus, als ob du den Operator =~ auseinandergeschrieben hast; = ~ ist nicht dasselbe wie =~.

    Gruß
  11. Pauline25

    Pauline25 Grünschnabel

    [perl] #!/usr/bin/perl
    use strict;
    use warnings;

    my $in;
    my $data;
    my @array;
    my $array;


    open $in, '<', "Genomteil.gff" or die $!;
    while ($data = <$in>) {
    @array = split(/\t/, $data);



    # w = word character [A-z, 0-9]
    # W = non word charcter
    # * = must occour 0 or more times
    # d = same as [0-9]
    # + = 1 or more times


    my $GeneID = $1 if ($array [8] =~ /\w+\W+;db_xref=GeneID:(\d+)\n/) print $1;


    };

    close $in; [/perl]


    =~ hab ich jetzt zusammen.

    Beispieldaten:
    NC_014171.1 RefSeq gene 283 1623 . + . ID=NC_014171.1:dnaA;locus_tag=BMB171_C0001;db_xref=GeneID:9196130
    NC_014171.1 RefSeq gene 1802 2947 . + . ID=NC_014171.1:dnaN1;locus_tag=BMB171_C0002;db_xref=GeneID:9191043

    Gruß
  12. deepthroat

    deepthroat Premium-User

    Dein Programm ist ungültig. (Syntaxfehler)

    Dann kann dein reg. Ausdruck keinesfalls zutreffen. Du spezifizierst, das vor ";db_xref=GeneID" (mind.) ein non-word Zeichen und davor (mind.) ein word Zeichen stehen soll.

    In deinen Daten steht aber vor ";db_xref=GeneID" ein word Zeichen, kein non-word Zeichen.

    Wolltest du evlt. eine Alternative, a la (a|b) angeben?

    Gruß
  13. Pauline25

    Pauline25 Grünschnabel

    Ah, verstehe. Ich probiere es mal mit der Alternative.

    Vielen Dank erst mal.

    LG
  14. deepthroat

    deepthroat Premium-User

    Wobei eine Alternative (\w|\W)+ ziemlich sinnfrei ist. Im Grunde willst du doch beliebige Zeichen vor dem ";db_xref=GeneID" zulassen, oder nicht?

    Gruß
  15. Pauline25

    Pauline25 Grünschnabel

    Ja, das stimmt. Ich habe es jetzt mit .* probiert:

    [perl]my $GeneID = $1 if ($array [8] =~ /\.*;db_xref=GeneID:(\d+)\n/) print $GeneID;
    }; [/perl]

    Das trifft es wohl eher. Trotzdem stimmt irgendwas noch nicht. Anscheinend gibt es in der Zeile oben noch einen Syntax Fehler (nähe print), den ich nicht sehe.

    LG
  16. Pauline25

    Pauline25 Grünschnabel

    Es hat sich erledigt, ich habe $1 hinter den if-Befehl gesetzt, jetzt geht es. Hier die richtige Lösung, falls mal jemand ähnliche Probleme hat:

    [perl] #!/usr/bin/perl
    use strict;
    use warnings;

    my $in;
    my $data;
    my @array;
    my $array;
    my $GeneID;



    open $in, '<', "Genomteil.gff" or die $!;
    while ($data = <$in>) {
    @array = split(/\t/, $data);

    if ($array [8] =~ /\.*\;db_xref=GeneID:(\d+)\n/)

    {$GeneID = $1;


    print $GeneID;

    };
    }


    close $in; [/perl]

    Vielen Dank für die Hilfe.
    LG
    Zuletzt bearbeitet: 9. August 2011
  17. deepthroat

    deepthroat Premium-User

    Hi.

    Noch ein Hinweis zu deinem reg. Ausdruck:
    Code (Text):
    1. /\.*\;db_xref=GeneID:(\d+)\n/
    Du beginnst mit \.* und hast dabei das "." Metazeichen entwertet. D.h. dieser Ausdruck passt auf eine beliebige Anzahl von Punkten (0 bis n). Du hast vor dem ;db_xref allerdings gar keine Punkte stehen.

    Da du den * Quantifizierer spezifiziert hast, spielt das keine Rolle, da ein leeres Wort in jedem Text enthalten ist und an jeder Stelle übereinstimmt.

    Meintest du evtl. einfach '.*' ?

    Dann wäre allerdings diese Angabe auch unnötig. Da .* einfach immer und überall paßt.

    Es reicht also aus zu schreiben: /;db_xref=GeneID:(\d+)\n/ Das kommt exakt auf's Gleiche raus, du hast es nur komplizierter ausgedrückt.

    (ein Semikolon mußt du nicht entwerten, es ist kein Metazeichen)

    Gruß
  18. Pauline25

    Pauline25 Grünschnabel

    Hm, aller Anfang ist schwer. Hast vollkommen recht mit den Anmerkungen. Ich meinte tatsächlich '.*' und ja, es ist total überflüssig in diesem Fall - hätt ich aber selbst merken sollen.
    Danke für die super Hilfe!! Jetzt mach ich mich an den nächsten Schritt....

    LG
  19. Pauline25

    Pauline25 Grünschnabel

    Ein paar Schritte weiter und schon taucht das nächste Problem auf! Hier noch mal ein Auszug der Textdatei, die ich bearbeiten möchte:

    NC_014171.1 RefSeq gene 14311 14425 . + . ID=NC_014171.1:rrs_1;locus_tag=BMB171_C5091;db_xref=GeneID:9190898
    NC_014171.1 RefSeq exon 14311 14425 . + . ID=NC_014171.1:rrs_1:unknown_transcript_1;Parent=NC_014171.1:rrs_1;gbkey=rRNA;locus_tag=BMB171_C5091;product=5S ribosomal RNA;db_xref=GeneID:9190898;exon_number=1
    NC_014171.1 RefSeq gene 14459 15460 . - . locus_tag=BMB171_C0007;db_xref=GeneID:9190899
    NC_014171.1 RefSeq CDS 14462 15460 . - 0 locus_tag=BMB171_C0007;transl_table=11;product=hypothetical protein;protein_id=YP_003662545.1;db_xref=GI:296500845;db_xref=GeneID:9190899;exon_number=1

    Für meine Frage muss ich wohl etwas ausholen, also hier das gesamt Skript mit Kommentaren:

    [perl]# Task: Extract GeneID-Number from the .Gff file

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

    my $in;
    my $data;
    my @array;
    my $array;
    my $GeneID;
    my @BMB;
    my $BMB;
    my $flag = 0;
    my %hash;
    my $hash;


    # 1) open the .gff Inputfile and while reading line by line split $data at each tab and put them in the @array


    open $in, '<', "Genomteil.gff" or die $!;

    while ($data = <$in>) {

    @array = split(/\t/, $data);

    if ($array [2] =~/gene/){ #wenn 'gene auftaucht, anfangen Daten zu extrahieren)
    $flag = 1;

    @BMB = ($array[3], $array[4], $array[6]); #extrahierte Daten in neues Array, das später als value ins Hash gespeichert wird


    }



    if ($array[2] =~/CDS/){

    push (@BMB, $array[2]);

    #weitere Daten des zu bearbeitenden Blockes extrahieren und Array hinzufügen

    } elsif ($array[2] =~/exon/){

    push (@BMB, $array[2]);

    }


    if ($array[8] =~ /.*;db_xref=GeneID:(\d+)\n/) { #wenn GeneID auftaucht, die folgende Nummer extrahieren und als Key in Hash einfügen. Dann das @BMB mit den values zum Hash hinzufügen

    $GeneID = $1;

    @{$hash {$GeneID}} = @BMB;

    }



    if ($array [8]=~ /.*;exon_number=1/){ #hier endet der Block mit den wichtigen Daten des ersten Teils meiner Datei
    $flag = 0;

    }

    }

    close $in;

    while ( ($GeneID, $BMB) = each %hash) {
    print "$GeneID => $BMB[0]\n";
    }
    [/perl]

    So, nun meine Erkenntnis: Skript funktioniert soweit, mein Array @BMB wird aber immer wieder mit den Werten des nächsten Abschnitts überschrieben, so dass am Ende nur noch die Daten des letzten Blockes übrig sind (die keys werden allerding alle im Hash gespeichert). Meine Aufgabe um dieses Problem zu lösen lautet nun explizit: Baue einen zweiten flip-flop ein, damit die beiden immer abwechselnd angesprochen werden. Also flip-flop 1 spricht die Daten des ersten Blockes an, und speichert alles im Array, flip-flop 2 erkennt dann, das ein neuer Block mit neuen Daten kommt u.s.w.
    Hab mich jetzt durch etliche Foren etc. gegoogelt, aber immer noch keine Idee, wie ich das ins Skript einbauen soll.

    Weiß jemand Rat?

    Danke euch schon mal.

    Lieben Gruß

Diese Seite empfehlen