2009-09-18 7 views
7

Ich versuche herauszufinden, die richtige PBP genehmigte Möglichkeit, eine Multi-Line-String Zeile für Zeile zu verarbeiten. Viele Perl-Codierer schlagen vor, die mehrzeilige Zeichenfolge als Dateihandle zu behandeln, was gut funktioniert, wenn Sie in Ihrem Skript nicht "use strict" verwenden. Dann erhalten Sie vom Compiler eine Warnung, dass Sie keine Zeichenfolge als Symbol verwenden dürfen, während strikte Referenzen verwendet werden.Wie kann ich eine mehrzeilige Zeichenfolge Zeile für Zeile in Perl verarbeiten?

Hier ist ein einfaches Ausführungsbeispiel des Problems:

#use strict; 
use warnings; 

my $return = `dir`; 
my $ResultsHandle = ""; 
my $matchLines = ""; 
my $resultLine = ""; 
open $ResultsHandle, '<', \$return; 
while (defined ($resultLine = <$ResultsHandle>)) { 
    if ($resultLine =~ m/joe/) { 
     $matchLines = $matchLines . "\t" . $resultLine; 
    } 
} 
close($ResultsHandle); 
print "Original string: \n$return\n"; 
print "Found these matching lines: \n$matchLines\n"; 

Beachten Sie, dass die "use strict" Line-Out wird kommentiert. Als ich dieses Skript ohne Verwendung streng laufen, bekomme ich, was ich will und erwarten:

Original string: 
Volume in drive D has no label. 
Volume Serial Number is 50D3-54A6 

Directory of D:\Documents and Settings\username\My Documents\Eclipse\myTestProject 

09/18/2009 11:38 AM <DIR>   . 
09/18/2009 11:38 AM <DIR>   .. 
09/18/2009 11:36 AM    394 .project 
09/18/2009 11:37 AM     0 joe.txt 
09/18/2009 11:37 AM     0 joey.txt 
09/18/2009 11:38 AM     0 kurt.txt 
09/18/2009 11:43 AM    497 main.pl 
09/18/2009 11:38 AM     0 shane.txt 
       6 File(s)   891 bytes 
       2 Dir(s) 6,656,188,416 bytes free 

Found these matching lines: 
    09/18/2009 11:37 AM     0 joe.txt 
    09/18/2009 11:37 AM     0 joey.txt 

Hier ist das Problem, though. Als ich die "use strict" Zeile Kommentar-, erhalte ich die folgende Warnung oder einen Fehler von Perl:

Can't use string ("") as a symbol ref while "strict refs" in use at D:/Documents and Settings/username/My Documents/Eclipse/myTestProject/main.pl line 8. 

Linie 8 die "offen $ ResultsHandle, '<', \ $ return;" Linie, nebenbei bemerkt. Da Perl Best Practices mich dazu zwingen, strict zu verwenden, wie erwartet PBP, dass ich eine Multiline-Zeichenkette Zeile für Zeile verarbeite? Irgendwelche Vorschläge von der SO-Community?

Danke!

+4

Wenn Sie sich über Best Practices wollen reden, ich schlage vor, Sie bei all Ihren Variableninitialisierung einen Blick darauf werfen, auf die Art und Weise Sie Variablen definieren, wie in altmodischer C (an der Spitze), und Ihre Verwendung von Backticks für etwas, das von Perl selbst leicht erreicht werden kann. – innaM

+1

Danke, Manni. Der Abruf von Verzeichnisinhalten diente nur zu Demonstrationszwecken. Mein aktuelles Programm ruft tatsächlich ein anderes Programm auf und verarbeitet seine Ausgabe. Und die altmodische variable Initialisierung ist etwas, an dem ich mehr arbeiten muss. Aber ich schneide oft aus alten Skripten und füge das ein. :-) Ich versuche es aber besser zu machen. –

Antwort

11

initialisiere nicht $ResultsHandle:

use strict; 
use warnings; 

my $return = `dir`; 
my $ResultsHandle; # <-- leave undefined 
my $matchLines = ""; 
my $resultLine = ""; 
open $ResultsHandle, '<', \$return; 
while (defined ($resultLine = <$ResultsHandle>)) { 
    if ($resultLine =~ m/joe/) { 
     $matchLines = $matchLines . "\t" . $resultLine; 
    } 
} 
close($ResultsHandle); 
print "Original string: \n$return\n"; 
print "Found these matching lines: \n$matchLines\n"; 

Wenn Sie $ResultsHandle undefined vor demverlassen, wird es mit einem Verweis auf das Dateihandle ausgefüllt. Da Sie es auf eine Zeichenfolge festgelegt haben, wurde open() angenommen, dass es sich stattdessen um eine symbolische Referenz auf eine Variable handeln sollte --- nicht zulässig unter use strict.

+0

Wow. Vielen Dank! Zeigt wie wenig ich über Perl weiß! Ich denke, ich dachte, ich müsste es auf ETWAS initialisieren. Ich vermute, ich lag falsch. Danke für die schnelle Antwort! –

+0

Zeigt auch, dass ich überhaupt nicht "streng" verstehe. Ich habe nur versucht, den Compiler und das Perl Critic-Modul zufrieden zu stellen, ohne alle Nachrichten vollständig zu verstehen, die sie beide generiert haben. –

+2

Eine andere Möglichkeit, darüber nachzudenken: 'open()' initialisiert '$ ResultsHandle' für Sie, * wenn es nicht bereits initialisiert ist *. 'use strict' verbietet Dinge, die gelegentlich nützlich sein können, aber öfter Probleme verursachen. – dave4420

3

umrechnen mehrzeiligen Zeichenfolge in eine Liste von einzelnen Zeile Strings mit split:

my @resultLines = split /\n/, $result;  # or /\r\n/ for Windows? 
foreach my $resultLine (@resultLines) { 
    if ($resultLine =~ m/joe/) { 
     $matchLines 
      = $matchLines . "\t" 
       . $resultLine . "\n"; # put \n or \r\n back on the end 
    } 
} 
+0

Wenn Sie '\ n' als Zeilentrennzeichen verwenden, werden der Variablen $ resultLine keine \ n Zeichen zugewiesen. Verwenden Sie besser split/^/m, $ result, es wird ganze Zeile mit Zeilenende zugewiesen. Sei geduldig, die letzte Zeile hat nicht immer Zeichen am Ende der Zeile. – Znik

0

Öffnen Sie ein Dateihandle ein Rohr von „dir“ -Befehl.

z.

open my $FOO, "dir|" or die "Can not run 'dir': $!"; 
+2

In der Tat. Wenn "dir" ein Muss ist, geh für die Pfeife. Aber ich würde lieber readdir oder einen einfachen Glob verwenden. – innaM

2

ändern

my $ResultsHandle = ""; 

zu

my $ResultsHandle; 
7

Der prägnante PBP Weg ist open wie so zu verwenden:

open my $ResultsHandle, '<', \$return; 

dies die Notwendigkeit für das früher beseitigt "my $ Resultshandle;" Erklärung und vermeidet die strikte Warnung, dass Sie lief.

4

Sie können auch einen regulären Ausdruck als Iterator verwenden:

my $data = q{Hello 
This 
Is 
A 
Test}; 

while($data =~ /(.+)$/mg) { 
    print "line is '$1'\n"; 
} 

Dies ist etwas weniger gewunden im Vergleich zu einer Dateikennung verwendet, die eine Zeichenfolge darstellt.

0

besseres Ergebnis mit Split kann erfolgen durch:

my $result="LINE1 
line2 
linE3 
"; 
#attention, /^/m allows properly operate on multiline string using regex 
#and^is character empty begin all lines 
foreach my $resultLine (split /^/m, $result) { 
    print $resultline; #withount '\n' because it have got 
    #some checks & operations 
} 
Verwandte Themen