8

我试图找出正确的 PBP 批准的方式来一次处理多行字符串。许多 Perl 编码人员建议将多行字符串视为文件句柄,除非您在脚本中使用“use strict”,否则它可以正常工作。然后你会从编译器那里得到一个警告,说在使用严格引用时不能将字符串用作符号。

这是该问题的一个简单的工作示例:

#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

不过,这就是问题所在。当我取消注释“use strict”行时,我从 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 行是“打开 $ResultsHandle, '<', \$return;” 顺便说一句,线。因此,既然 Perl 最佳实践要求我使用严格,那么 PBP 如何期望我一次处理多行字符串?SO社区有什么建议吗?

谢谢!

4

7 回答 7

11

不要初始化$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.

于 2009-09-18T16:03:40.623 回答
7

更简洁的 PBP 方式是这样使用open

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

这消除了对早期“我的 $Resulthandle;”的需要。声明并避免招致您遇到的严格警告。

于 2009-09-18T16:15:24.423 回答
4

您还可以使用正则表达式作为迭代器:

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

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

与使用表示字符串的文件句柄相比,这稍微不那么复杂。

于 2009-09-18T17:00:07.593 回答
3

将多行字符串转换为单行字符串列表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
    }
}
于 2009-09-18T15:57:58.133 回答
2

改变

my $ResultsHandle = "";

my $ResultsHandle;
于 2009-09-18T16:02:02.950 回答
0

使用“dir”命令中的管道打开文件句柄。

例如

open my $FOO, "dir|" or die "Can not run 'dir': $!";
于 2009-09-18T16:00:22.003 回答
0

可以通过以下方式获得更好的拆分结果:

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
}
于 2016-12-08T09:33:20.947 回答