2012-04-18 4 views
1

現在、ファイル内のテーブルからREGEX行のマッチを使ってテーブル行に対して値を抽出しています。IF文の正規表現マッチ(Perl)からの値

foreach my $line (split("\n", $file)) { 
    if ($line =~ /^(\S+)\s*(\S+)\s*(\S+)$/) { 
     my ($val1, $val2, $val3) = ($1, $2, $3); 

     # $val's used here 
    } 
} 

私は意図的にコードを明確にするために値を割り当てます。私のテーブル行の中には、10個以上のval(aka columns)が含まれています。 - val = $($ 1、$ 2、...、$ n)ではなくvalを割り当てるより効率的な方法がありますか?

+0

http://stackoverflow.com/questions/2304577/how-can-i-store-regex-captures-in-an-array-in-perl? – Scroog1

+2

私はいつもsplitを使用するhttp://stackoverflow.com/questions/874915/perl-extracting-data-from-text-using-regexが好きです。あなたの正規表現は候補者のようです。 – Konerak

答えて

8

リストコンテキストで一致すると、キャプチャグループのリストが生成されます。失敗した場合は、空のリストを返します。これはfalseです。したがって、

if(my ($val1, $val2, $val3) = $line =~ m/^(\S+)\s*(\S+)\s*(\S+)$/) { 
    ... 
} 

ただし、このコードでは多くの赤旗が明白です。その正規表現のキャプチャは分割と非常によく似ています:

if(my ($val2, $val2, $val3) = split ' ', $line) { 
    ... 
} 

次に、なぜ$ fileをlinefeedsで分割するのですか?あなただけのスペースでテーブルを使用しているdelimiter.Youはsplit機能を使用することができるように

while(my $line = <$fh>) { 
    ... 
} 
+0

'split ''の代わりに' split/\ s +/'を使う傾向があります –

+1

@LeonardoHerreraなぜですか?先頭に空白がある場合は、先頭のヌルフィールドが保持されます。 – TLP

+0

分割のために正規表現を入れ替えることに注意してください。同じことを意味するわけではありません。 '$ line = 'abc def' ;; –

1

が見える:あなたは、ファイルの内容を読んでいる場合は、はるかに良く、実際に一度に単一のラインを読むことです

@valuearray = split(" ", $line)

そしてとしての要素を扱う:

@valuearray[0] ,@valuearray[1]など。

+0

入力いただきありがとうございます。私が提供した例は簡略化されています。私のレポートのデリミタは実際には一貫していません。 – kaspnord

+0

@kaspnord splitは完全な正規表現をサポートしています。同じテーブル内の異なる区切り文字であっても、任意の区切り文字を使用できます。 – byrondrossos

2

私はそうならば、それは動作しませんので、これは、あなたの実際のコードではないことを前提としています

foreach my $line (split("\n", $file)) { 
    if ($line =~ /^(\S+)\s*(\S+)\s*(\S+)$/) { 
     my ($val1, $val2, $val3) = ($1, $2, $3); 
    } 
# all the $valX variables are now out of scope 
} 

あなたはまた\s*も空の文字列に一致することに注意する必要があり、微妙なエラーが発生することがあります。たとえば:

"a bug" =~ /^(\S+)\s*(\S+)\s*(\S+)$/; 
# the captures are now: $1 = "a"; $2 = "bu"; $3 = "g" 

でも\S+は貪欲であるという事実にもかかわらず、アンカー^ ... $は空の文字列は単語を分割することができ、したがって、収まるように正規表現を強制します。

空白で区切られたすべての単語をキャプチャする場合は、splitを使用することをお勧めします。

open my $fh, "<", "file.txt" or die $!; 
my @stored; 
while (<$fh>) { 
    my @vals = split; 
    push(@stored, \@vals) if @vals; # ignore empty values 
} 

これは、キャプチャされた値を2次元配列に格納します。何らかの理由でファイル全体を実際にメモリに保存する必要がないかぎり、ファイルハンドルを直接使用して行単位で読み取ることをお勧めします。

+0

あなたのご意見ありがとうございます。 $ val変数の範囲を明確にするために質問を更新しました。あなたの例の 'split'はさまざまな数の空白を扱いますか?残念ながら、あなたの例を使って明示的にvalの名前を付けることはできません。ファイル処理に関するLeoNerdの投稿に関する私のコメントを参照してください。 – kaspnord

+0

@kaspnordはい、配列に分割すると、いくつでも一致します。空白の数が問題である場合、例えば、 "a \ t \ tc"が '$ val1 =" a "であると仮定されている場合; $ val3 = "c" '(' $ val2'をスキップする)。しかし、あなたはCSVモジュールを使う方が良いでしょう。必要な変数の数がわからない場合は、配列を使用します。必要があると思われる場合は、配列要素を簡単に数え、後で名前付き変数に割り当てることができます。ファイルをスラッシングする必要はない(通常はそうではない)ので、パフォーマンスが低下します。しかしそれは別の質問です。 – TLP