2012-05-14 17 views
8

Ich habe Text wie folgt aus:Perl Regex zum Extrahieren von mehrzeiligen Blöcke

00:00 stuff 
00:01 more stuff 
multi line 
    and going 
00:02 still 
    have 

Also, ich habe keinen Block Ende haben, gerade einen neuen Block.

Ich möchte alle Blöcke rekursiv erhalten:

1 = 00:00 stuff 
2 = 00:01 more stuff 
multi line 
    and going 

etc

Der Balg Code gibt mir nur dieses:

$VAR1 = '00:00'; 
$VAR2 = ''; 
$VAR3 = '00:01'; 
$VAR4 = ''; 
$VAR5 = '00:02'; 
$VAR6 = ''; 

Was mache ich falsch?

my $text = '00:00 stuff 
00:01 more stuff 
multi line 
and going 
00:02 still 
have 
    '; 
my @array = $text =~ m/^([0-9]{2}:[0-9]{2})(.*?)/gms; 
print Dumper(@array); 

Antwort

2

Dies sollte den Trick. Anfang der nächsten \ d \ d: \ d \ d wird als Blockende behandelt.

$Str = '00:00 stuff 
00:01 more stuff 
multi line 
    and going 
00:02 still 
    have 
00:03 still 
    have' ; 

@Blocks = ($Str =~ m#(\d\d:\d\d.+?(?:(?=\d\d:\d\d)|$))#gs); 

print join "--\n", @Blocks; 
+1

Ihre Nicht-Erfassung Pars '(?: ...)' sind hier überflüssig, da '(=. ..) 'kann auch wechseln. Außerdem merke ich, dass Sie immer noch nicht "strikten" Code schreiben, der in meinem Buch schlecht ist, da es schlechte Praktiken fördert. – TLP

+1

Ich habe eine ausreichende Erklärung über ** Verwendung (ing) strict ** im anderen Thread gegeben. Macht es Ihnen etwas aus, damit aufzuhören? – tuxuday

+1

Ja, es macht mir etwas aus. Würden Sie bitte aufhören, nicht-strikten Code zu posten? Dies ist eine Lernumgebung, es kostet Sie * nichts *, Code zu schreiben, der gute Praktiken fördert, oder? – TLP

0

Ihr Problem ist, dass .*? ist nicht gierig auf die gleiche Art und Weise, dass .* gierig ist. Wenn es nicht erzwungen wird, passt es so wenig wie möglich an, was in diesem Fall die leere Zeichenfolge ist.

Sie brauchen also etwas nach dem nicht-gierigen Match, um Ihre Aufnahme zu verankern. Ich kam mit dieser Regex up:

my @array = $text =~ m/\n?([0-9]{2}:[0-9]{2}.*?)(?=\n[0-9]{2}:|$)/gs; 

Wie Sie sehen, habe ich entfernt die /m Option genau zu der Lage sein, Ende der Zeichenkette in der Vorgriff Behauptung übereinstimmen.

Sie könnten auch diese Lösung betrachten:

my @array = split /(?=[0-9]{2}:[0-9]{2})/, $text; 
4

Version 5.10.0 eingeführt named capture groups, die für die Anpassung nicht triviale Muster nützlich sind.

(?'NAME'pattern)
(?<NAME>pattern)

Eine benannte Capture-Gruppe. In jeder Hinsicht identisch zu normalen Capturing Klammern () aber für die weitere Tatsache, dass die Gruppe mit Namen in verschiedenen regulärem Ausdruck Konstrukten (wie \g{NAME}) bezeichnet werden kann und über %+ oder %- nach Namen nach einem erfolgreichen Spiel zugegriffen werden. Weitere Details zu den Hashes %+ und %- finden Sie unter perlvar.

Wenn mehrere unterschiedliche Erfassungsgruppen den gleichen Namen haben, bezieht sich $+{NAME} auf die am weitesten links stehende Gruppe in der Übereinstimmung. Die Formulare (?'NAME'pattern) und (?<NAME>pattern) sind äquivalent.

Mit benannten Capture-Gruppen können wir Submuster im Regex wie folgt benennen.

use 5.10.0; # named capture buffers 

my $block_pattern = qr/ 
    (?<time>(?&_time)) (?&_sp) (?<desc>(?&_desc)) 

    (?(DEFINE) 
    # timestamp at logical beginning-of-line 
    (?<_time> (?m:^) [0-9][0-9]:[0-9][0-9]) 

    # runs of spaces or tabs 
    (?<_sp> [ \t]+) 

    # description is everything through the end of the record 
    (?<_desc> 
     # s switch makes . match newline too 
     (?s: .+?) 

     # terminate before optional whitespace (which we remove) followed 
     # by either end-of-string or the start of another block 
     (?= (?&_sp)? (?: $ | (?&_time))) 
    ) 
) 
/x; 

es wie in

my $text = '00:00 stuff 
00:01 more stuff 
multi line 
and going 
00:02 still 
have 
    '; 

while ($text =~ /$block_pattern/g) { 
    print "time=[$+{time}]\n", 
     "desc=[[[\n", 
     $+{desc}, 
     "]]]\n\n"; 
} 

Ausgabe verwenden:

$ ./blocks-demo 
time=[00:00] 
desc=[[[ 
stuff 
]]] 

time=[00:01] 
desc=[[[ 
more stuff 
multi line 
and going 
]]] 

time=[00:02] 
desc=[[[ 
still 
have 
]]]
+1

Wirklich tolles Beispiel für moderne Perl5 :) – XoR

Verwandte Themen