Как я могу обработать многострочную строку по одной строке в Perl с использованием строгого на месте?
Я пытаюсь найти подходящий способ, одобренный PBP, для обработки многострочной строки по одной строке за раз. Многие Perl-кодеры предлагают рассматривать многострочную строку как дескриптор файла, который прекрасно работает, если в вашем скрипте не используется "строгий". Затем вы получите предупреждение от компилятора о невозможности использовать строку в качестве символа, когда используется строгая ссылка.
Вот простой рабочий пример проблемы:
#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";
Обратите внимание, что строка "использовать строго" закомментирована. Когда я запускаю этот скрипт без строгого использования, я получаю то, что хочу, и ожидаю:
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
Здесь проблема, однако. Когда я раскомментирую строку "использовать строго", я получаю следующее предупреждение или ошибку от 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.
Строка 8 - это "open $ResultsHandle, '<', \ $ return;" линия, кстати. Итак, поскольку Perl Best Practices требует от меня строгого, как PBP ожидает, что я буду обрабатывать многострочную строку по одной строке за раз? Любые предложения от SO сообщества?
Спасибо!
7 ответов
Не инициализировать $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";
Если ты уйдешь $ResultsHandle
неопределенный до open()
, он будет заполнен ссылкой на дескриптор файла. Потому что вы устанавливали это в строку, open()
Предполагается, что вместо него предполагается символическая ссылка на переменную - не допускается use strict
,
Более краткий способ PBP - использовать open следующим образом:
open my $ResultsHandle, '<', \$return;
Это устраняет необходимость в этом ранее "my $Resultshandle;" декларации и избегает того строгого предупреждения, с которым вы столкнулись.
Вы также можете использовать регулярное выражение в качестве итератора:
my $data = q{Hello
This
Is
A
Test};
while( $data =~ /(.+)$/mg) {
print "line is '$1'\n";
}
Это немного менее запутанно по сравнению с использованием файлового дескриптора, который представляет строку.
Преобразуйте многострочную строку в список однострочных строк с 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
}
}
Лучший результат с разделением можно сделать:
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
}
Откройте дескриптор файла, используя канал из команды "dir".
Например
open my $FOO, "dir|" or die "Can not run 'dir': $!";