如何使用严格到位的perl一次处理一行多行字符串?

时间:2009-09-18 15:53:09

标签: perl string multiline filehandle

我正在尝试找出正确的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,'&lt;',\ $ return;”顺便说一下。因此,由于Perl Best Practices要求我使用严格,PBP如何期望我一次处理一行多行字符串?来自SO社区的任何建议?

谢谢!

7 个答案:

答案 0 :(得分: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下允许的。

答案 1 :(得分:7)

更简洁的PBP方式是如此使用open

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

这消除了之前“my $ Resultshandle”的需要。声明并避免招致您遇到的严格警告。

答案 2 :(得分:4)

您还可以使用regexp作为迭代器:

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

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

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

答案 3 :(得分: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
    }
}

答案 4 :(得分:2)

更改

my $ResultsHandle = "";

my $ResultsHandle;

答案 5 :(得分:0)

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

E.g。

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

答案 6 :(得分: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
}