2009-09-18 17 views
7

私は、一度に複数行の文字列を1行ずつ処理する適切なPBP承認方法を理解しようとしています。多くのPerlコーダーは、マルチライン文字列をファイルハンドルとして扱うことを推奨しています。これは、あなたのスクリプトで "厳密に"使用しない限りうまくいきます。厳密な参照が使用されている間、文字列をシンボルとして使用できないという警告がコンパイラから出されます。コメントアウトされたライン「厳格を使用する」というperlで複数行の文字列を一度に1行ずつ処理するにはどうしたらよいですか?

#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行目の「オープン$ ResultsHandle、 『<』、\ $のリターン;」でありますところで、ライン。だから、Perlのベストプラクティスでは厳密に使う必要があるので、PBPは一度に複数行の文字列を1行ずつ処理することをどのように期待していますか? SOコミュニティからの提案はありますか?

ありがとうございます!

+4

、私はあなたがオールド・ファッションドのように変数を定義する方法で、すべての変数の初期化を見てみましょう示唆しますC(上の方)と、Perl自身が簡単に達成できる何かのためのbackticksの使用。 – innaM

+1

ありがとう、Manni。ディレクトリコンテンツの取得はデモンストレーションの目的にすぎませんでした。私の実際のプログラムは、実際に別のプログラムを呼び出し、出力を処理します。そして、旧式の変数の初期化は、私がより多くのことを行うために必要なものです。しかし、私はしばしば古いスクリプトから切り取って貼り付けます。これが私の得意です。 :-)私はもっとうまくやろうとしています。 –

答えて

11

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

うわー。ありがとう!私がPerlについてどれほど知っているかわかりません!私はそれを何かに初期化しなければならないと思った。私は間違っていたと思います。迅速な答えをありがとう! –

+0

また、私は「厳密」を全く理解していないことを示しています。私はコンパイラとPerlの批評家の両方のモジュールを喜んでしようとしています。 –

+2

もう一つ考えてみましょう: 'open()'はあなたのために '$ ResultsHandle'を初期化します。まだ初期化されていなければ*。 'use strict'は、時には有用なことを禁止しますが、より頻繁にトラブルを引き起こします。 – dave4420

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 
    } 
} 
+0

行区切り文字として '\ n'を使用すると、\ n文字を$ resultLine変数に代入しません。 split/^/m、$ resultを使うと、行末に行全体が割り当てられます。辛抱強くして、最後の行は終わりの行の文字を持っていません。 – Znik

0

を開き、「DIR」コマンドからパイプを使用してファイルハンドルを。

など。

my $ResultsHandle; 
+2

確かに。 "dir"が必須の場合は、パイプに行く。しかし、私はむしろreaddirまたは単純なglobを使用したいと思います。 – innaM

2

変更

my $ResultsHandle = ""; 

$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()は、代わりに変数へのシンボリックリファレンスであると推定されていました--- use strictの下には許可されていません。

7

より簡潔PBPの道はそうのようなopenを使用することです:

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

これは、以前の必要がなくなり、「私の$ Resultshandleを。」あなたが遭遇したことを警告する厳守が発生するのを避けます。

4

また、イテレータとして正規表現を使用することができます。

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

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

これは文字列を表し、ファイルハンドルを使用する場合と比較してわずかに少ない複雑です。スプリット付き

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 
} 
関連する問題