Как я могу обработать многострочную строку по одной строке в Perl с использованием строгого на месте? - PullRequest
8 голосов
/ 18 сентября 2009

Я пытаюсь найти подходящий способ, одобренный 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";

Обратите внимание, что строка "use strict" закомментирована. Когда я запускаю этот скрипт без строгого использования, я получаю то, что хочу, и ожидаю:

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 сообщества? </p>

Спасибо!

Ответы [ 7 ]

11 голосов
/ 18 сентября 2009

Не инициализировать $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.

7 голосов
/ 18 сентября 2009

Более краткий способ PBP - использовать open примерно так:

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

Это устраняет необходимость в более раннем "my $ Resultshandle;" объявление и избегает того, чтобы строгое предупреждение, что вы столкнулись.

4 голосов
/ 18 сентября 2009

Вы также можете использовать регулярное выражение в качестве итератора:

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

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

Это немного менее запутанно по сравнению с использованием файлового дескриптора, который представляет строку.

3 голосов
/ 18 сентября 2009

Преобразование многострочной строки в список однострочных строк с помощью 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
    }
}
2 голосов
/ 18 сентября 2009

Изменение

my $ResultsHandle = "";

до

my $ResultsHandle;
0 голосов
/ 08 декабря 2016

Лучший результат с разделением можно получить:

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
}
0 голосов
/ 18 сентября 2009

Открыть дескриптор файла с помощью канала из команды "dir".

например.

open my $FOO, "dir|" or die "Can not run 'dir': $!";
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...