Come posso elaborare una stringa a più righe una riga alla volta in perl con un uso rigoroso in atto?
-
22-07-2019 - |
Domanda
Sto cercando di capire il modo corretto PBP approvato per elaborare una stringa a più righe una riga alla volta. Molti programmatori Perl suggeriscono di trattare la stringa multilinea come un filehandle, che funziona bene a meno che tu non abbia & Quot; usa il rigoroso & Quot; nella tua sceneggiatura. Quindi viene visualizzato un avviso dal compilatore per non essere in grado di utilizzare una stringa come simbolo mentre sono in uso rigidi riferimenti.
Ecco un semplice esempio funzionante del problema:
#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";
Nota che il " usa il rigoroso " la riga è commentata. Quando eseguo questo script senza usare rigoroso, ottengo ciò che voglio e mi aspetto:
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
Ecco il problema, però. Quando decomprimo il & Quot; uso il rigoroso & Quot; riga, ricevo il seguente avviso o errore da 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.
La riga 8 è la quot! &; apri $ ResultsHandle, '<', \ $ return; " linea, a proposito. Quindi, poiché le best practice del Perl mi richiedono di usare rigorose, come si aspetta che PBP elabori una stringa multi linea una riga alla volta? Qualche suggerimento da parte della comunità SO?
Grazie!
Soluzione
Non inizializzare $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";
Se si lascia open()
non definito prima di use strict
, verrà compilato con un riferimento all'handle del file. Dato che lo stavi impostando su una stringa, <=> presumeva che avrebbe dovuto essere invece un riferimento simbolico a una variabile --- non consentito in <=>.
Altri suggerimenti
Il modo PBP più conciso è utilizzare open in questo modo:
open my $ResultsHandle, '<', \$return;
Questo elimina la necessità di quella precedente " my $ Resultshandle; " dichiarazione ed evita di incorrere in quel rigoroso avvertimento in cui ti sei imbattuto.
Puoi anche usare un regexp come iteratore:
my $data = q{Hello
This
Is
A
Test};
while( $data =~ /(.+)$/mg) {
print "line is '$1'\n";
}
Questo è leggermente meno contorto rispetto all'uso di un filehandle che rappresenta una stringa.
Converti la stringa a più righe in un elenco di stringhe a riga singola con 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
}
}
Cambia
my $ResultsHandle = "";
a
my $ResultsHandle;
Apri un filehandle usando una pipe da " dir " comando.
es.
open my $FOO, "dir|" or die "Can not run 'dir': $!";
Il risultato migliore con la divisione può essere ottenuto tramite:
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
}