2017-04-20 3 views
1

Meine Regex stimmt nur mit einigen der Ausdrücke überein. Wenn ich den Ausdruck auf regex101.com teste, funktioniert es gut ... was könnte das Problem mit meinem Code sein?Perl: Regex nur einige Male passend

Vielen Dank für Ihre Hilfe im Voraus.

Beispieldatei "surfacecoating":

[ 
('amino acids', 339, 350), 
('copper', 71, 77), 
('copper', 0, 6), 
('copper', 291, 297), 
('amino acids', 119, 130)] 

Was Dumper ausdruckt für diese Datei (beachten Sie die ersten 3 Spiele werden nicht zurückgegeben):

'surfacecoating' => { 
     'copper' => '291', 
     'amino acids' => '119' 
    }, 

der Code:

#!/usr/bin/perl 

use strict; 
use warnings; 
use Data::Dumper; 

determine_cde_instances(); 

sub determine_cde_instances { 
    my %cdeinstances; 
    my %cde_instances; 

    my $dir = "/results/CDE"; 
    opendir my $dh, $dir or die "Can't open $dir: $!"; 

    while (my $file = readdir($dh)) { 
     next if ($file =~ m/^\./); 
     next if -d $file; 

     open my $fh, '<', "$dir/$file" or die "Can't open $dir/$file: $!"; 

     while (my $line = <$fh>) 
     { 
       if (my ($instance) = $line =~ m/'(.*?)', (.*?), /)  
       { 
        my $instance = $1; 
        my $pos = $2; 
        $cde_instances{$file}{$instance} = $pos; 
       } 
     } 
     close $fh; 
    }  
    close $dh; 

    print Dumper(\%cde_instances); 
    return %cde_instances; 
} 
+1

Ihre Datendatei ist eine Sammlung von Sequenzen, aber Ihr Code erstellt ein (verschachteltes) assoziatives Array, das auf einem Mitglied der Sequenzen codiert ist. Ein [Array von Arrays] (http://perldoc.perl.org/perldsc.html#ARRAYS-OF-ARRAYS) stellt offensichtlich die Struktur in Ihrer Datendatei dar - aber welche Struktur möchten Sie im Code haben? Mit anderen Worten, was hätten Sie von 'Dumper' erwartet? – pilcrow

+0

Sie überschreiben wahrscheinlich alle 'cde_instance', während Sie sie zu' $ cde_instances' hinzufügen (es kann die erste Übereinstimmung als Schlüssel annehmen [nur eine Schätzung], was für '('copper', 0, 6) 'gleich ist und '('copper', 291, 297)'. Benutze einen anderen Schlüssel (anders als '$ instance') in:' $ cde_instances {$ file} {$ instance} = $ pos; ' –

Antwort

2

Sie speichern Informationen in einem Hashref mit den Schlüsseln $instance, aber einige dieser Schlüssel in Ihren Daten sind die gleich auf mehreren Zeilen. So wird der Schlüssel 'copper' wiederholt überschrieben, und Sie haben nur das letzte Vorkommen. Das gleiche passiert mit 'amino acids'.

Da diese Schlüsselworte to-be-hash-keys wiederholen, können Sie nicht mit einem geraden Hash gehen. Sie müssen sich eine andere Datenstruktur ausdenken, und die hängt davon ab, was Sie mit Daten tun müssen.

Eine sinnvolle Idee ist, eine Anordnung zu verwenden, und vielleicht einen Array mit hashrefs, einem für jedes Paar

if ($line =~ m/'(.*?)', (.*?), /)  
{ 
    my %instance_pos = ($1, $2); 

    push @{$cde_instances{$file}}, \%instance_pos; 
} 

Hier jeden Schlüssel $file in der Hash-%cde_instances hat einen ArrayRef als Wert, hashrefs für jede Trage Instanz-pos-Paar. Natürlich gibt es andere Möglichkeiten, dies ist eher ein Beispiel.

Dies kann auch als

if (my %instance_pos = $line =~ m/'(.*?)', (.*?), /) { 
    push @{$cde_instances{$file}}, \%instance_pos; 
} 

oder nur

if ($line =~ m/'(.*?)', (.*?), /) {  
    push @{$cde_instances{$file}}, {$1, $2}; 
} 

Wenn die Erfassungen dann auf zwei Variablen müssen überprüfen/validieren geschrieben werden von regex zuweisen.


Mit der obigen Änderung und use Data::Dump qw(dd); mit I

 
{ 
    "data.txt" => [ 
    { "amino acids" => 339 }, 
    { copper => 71 }, 
    { copper => 0 }, 
    { copper => 291 }, 
    { "amino acids" => 119 }, 
    ], 
} 

Hinweis erhalten zu drucken, dass die Zahlen auf der Linie nach dem ersten von Ihrem regex nicht erfaßt werden. Ich nehme an, dass das absichtlich gemacht wird. Bitte klären Sie es ist nicht so.

+0

Hallo! Vielen Dank, Ihre Erklärung ergab Sinn und ich sehe, wo ich falsch gelaufen bin, einen grundlegenden Aspekt der Hashes missverstanden. Ja, ich muss nur die erste Nummer speichern, nicht die zweite Nummer pro Zeile. Nochmals vielen Dank! – jelly

+0

@jelly Großartig, gut, das zu hören :) Ich habe ein paar weitere Möglichkeiten hinzugefügt, um diesen Code zu schreiben (wahrscheinlich nicht neu für Sie) – zdim

+0

Wie würde ich direkt auf die Schlüsselwerte von% instance_pos zugreifen? (ohne in eine Schleife zu gehen) wie $ cde_instances {$ file} {$ 1} – jelly