2017-03-22 2 views
1

Meine Frage ist die gleiche Frage wie How do I re.search or re.match on a whole file without reading it all into memory? aber anstelle von PythonPerl regex: Wie suche ich eine Datei nach einem mehrzeiligen Muster, ohne die ganze Datei in den Speicher zu schreiben?

Frage mit Perl: ich in der Lage sein wollen, einen regulären Ausdruck auf eine ganze Datei zu laufen, aber ich möchte in der Lage sein, nicht zu haben, um die ganze Datei sofort in den Speicher zu schreiben, da ich in Zukunft mit ziemlich großen Dateien arbeiten kann. Gibt es eine Möglichkeit, dies zu tun? Vielen Dank!

Erläuterung: Ich kann zeilenweise nicht lesen, da es mehrere Zeilen umfassen kann.

Warum verwende ich Perl anstelle von Python? Ich habe genug Probleme mit Python Regex, dass ich zu Perl wechseln muss. Ich würde https://pypi.python.org/pypi/regex installieren, aber ich kann nicht, da mein Arbeitsplatz verständlicherweise Schreibzugriff auf sein Python-Installationsverzeichnis nicht erlaubt, und ich würde lieber eine langsame hin und her E-Mail-Kette mit IT für sie, um es für mich zu installieren, und zu vermeiden/oder mit weiteren Berechtigungsproblemen behandeln :)

EDIT: Beispiel Muster ich suche

assign signal0 = (cond1) ? val1 : 
       (cond2) ? val2 : 
          val3; 

assign signal1[15:0] = {input1[7:0], input2[7:0]}; 

assign signal2[34:0] = { 4'b0, 
         subsig0[3:0], 
         subsig1, 
         subsig2, 
         subsig3[18:2], 
         subsig4[5:0] 
         }; 

ich bin für Muster wie die oben, dh eine variable Zuordnung nach oben suchen, bis ich ein Semikolon zu sehen. Die Regex würde mit jedem der obigen übereinstimmen, da ich nicht weiß, ob das Muster mehrzeilig ist oder nicht. Vielleicht so etwas wie /assign\s+\w+\s+=\s+[^;];/m, das heißt, bis ich ein Semikolon

EDIT2 sehen: (danke!) Aus den Antworten, dass das Muster in Start Zersetzen erscheint, mittlere, & Ende Abschnitte könnte die beste Strategie sein, z.B. Verwenden des Bereichsoperators wie von einigen vorgeschlagen.

+0

Sie würden also nur gerne den Teil behalten, dass Sie gegen in Speicher korrekt? Sie könnten dann versuchen, Zeilen progressivly lesen, bis Sie ein komplettes Spiel bekommen, und Linien am Anfang aufgeben, wenn es keine Warte Spiel –

+3

ist, so dass Ihr Unternehmen in Ordnung ist mit Sie Ihre Entwicklungsarbeit auf eine ganz andere Sprache wechseln, aber sie gewann‘ t lässt du ein Modul installieren ??? – ThisSuitIsBlackNot

+0

Haben Sie auch von [virtualenv] (http://docs.python-guide.org/en/latest/dev/virtualenvs/) gehört? Sie können alle gewünschten Module in Ihrem Home-Verzeichnis installieren, Sie benötigen keinen Root-Zugriff. – ThisSuitIsBlackNot

Antwort

4

Sie können die range operator verwenden, um alles zwischen zwei Mustern übereinstimmen, während line-by-line zu lesen:

use strict; 
use warnings 'all'; 

while (<DATA>) { 
    print if /^assign/.. /;/; 
} 

__DATA__ 
foo 
assign signal0 = (cond1) ? val1 : 
       (cond2) ? val2 : 
          val3; 
bar 
assign signal1[15:0] = {input1[7:0], input2[7:0]}; 
baz 
assign signal2[34:0] = { 4'b0, 
         subsig0[3:0], 
         subsig1, 
         subsig2, 
         subsig3[18:2], 
         subsig4[5:0] 
         }; 
qux 

Ausgang:

assign signal0 = (cond1) ? val1 : 
       (cond2) ? val2 : 
          val3; 
assign signal1[15:0] = {input1[7:0], input2[7:0]}; 
assign signal2[34:0] = { 4'b0, 
         subsig0[3:0], 
         subsig1, 
         subsig2, 
         subsig3[18:2], 
         subsig4[5:0] 
         }; 
2

ich zwei Lösungen vorstellen kann (ohne stark zu denken, vielleicht falsch, ich bin):

a) eine maximale Anzahl von passenden Zeichen verwenden, sagen 1024. 1) Lesen Sie doppelt so viele (2048) Zeichen in. 2) Versuchen Sie zu entsprechen. 3) Suche vorwärts um 1024 Zeichen. Wiederholen.

b) Verwenden Sie ein Start- und ein Endmuster, die in einer einzelnen Zeile übereinstimmen. Der dazwischen liegende Teil kann später getestet werden. Perls Flip-Flop-Operator kann in diesem Szenario verwendet werden.

Bearbeiten: Da die Frage aktualisiert wurde, scheint Lösung b) eine gute zu sein.

Das Startmuster wäre die Zuweisung, und das Endmuster wäre das Semikolon. Alles dazwischen kann verkettet und später auf Gültigkeit geprüft werden.

Beispiel:

my $assignment = ""; 
while (<>) { 
    if (/assign\s+\w+\s+=/ .. /;/) { 
     $assignment .= $_; 
    } else { 
     if ($assignment =~ /full regex/) { 
      # do something with the match 
     } 
     $assignment = ""; 
    } 
} 
1

Hier ein Beispiel, bei dem eine progressive Anpassung mit einem Muster für eine vorläufige Übereinstimmung verwendet wird:

use feature qw(say); 
use strict; 
use warnings; 

my $pre_match = qr{assign\s+\S+\s+=\s+}; 
my $regex = qr{($pre_match[^;]+;)}; 

my $line = ""; 
my $found_start = 0; 
while(<DATA>) { 
    if (!$found_start && /$pre_match/) { 
     $line = ""; 
     $found_start = 1; 
    } 
    if ($found_start) { 
     $line .= $_; 
     if ($line =~ /$regex/) { 
      say "Got match: '$1'"; 
      $found_start = 0; 
      $_ = substr $line, $+[0]; 
      redo; 
     } 
    } 
} 

__DATA__ 
assign signal0 = (cond1) ? val1 : 
       (cond2) ? val2 : 
          val3; 

assign signal1[15:0] = {input1[7:0], input2[7:0]}; 

assign signal2[34:0] = { 4'b0, 
         subsig0[3:0], 
         subsig1, 
         subsig2, 
         subsig3[18:2], 
         subsig4[5:0] 
         }; 

Ausgang:

Got match: 'assign signal0 = (cond1) ? val1 : 
       (cond2) ? val2 : 
          val3;' 
Got match: 'assign signal1[15:0] = {input1[7:0], input2[7:0]};' 
Got match: 'assign signal2[34:0] = { 4'b0, 
         subsig0[3:0], 
         subsig1, 
         subsig2, 
         subsig3[18:2], 
         subsig4[5:0] 
         };' 
3

Sie den Eingabedatensatz-Trenn $/; Linie Semikolon und lesen Zeile einstellen. Jede Zeile enthält eine Anweisung, einschließlich des abschließenden Semikolons. Dann wird die Anpassung trivial.

+0

Ich bin gerade an meinem Telefon und kann kein Beispiel hinzufügen. – simbabque

Verwandte Themen