2011-01-20 9 views
1

Perlのエキスパート - 私の問題を解決しようとする試みは、多くのコードに変わりつつあります。ここに私の問題があります:Perlのテキストの解析 - 固定された区切り構造が変更されています

私は、列データの間に可変量の空白を持つことができるテキストブロック(例)を持っています。私は単純な分割を使用していましたが、問題は現在、列 "コード"にデータ内のスペースが含まれていることです(最後の列でのみ説明しています)。定数と思われるもの(私はソース構造にアクセスできないか、ソース構造を制御していませんが)は、カラム間に最低3つのスペースがある(多分、それよりも少ないかもしれませんが)。

私はカラムデリミタトークンが "3スペース"であると言いたいと思います。そして、それぞれのデータを実際のカラムデータにトリミングします。

COL0 COL1 COL2 COL3   COL4 COL5 
    -  4 0.2  1  416489 463455 554 
      1 0.9  1   E1 
    0  3 1.4  14 E97-TEST 1 
    -  1 97.5 396   PASS Good 

私は6つの変数に値を取得しようとしています。

注:COL0に値がない可能性があります。 COL4はデータにスペースを含むことがあります。 COL5には値もスペースも含まれていない可能性があります。すべての固定書式設定はスペース(タブやその他の特殊文字なし)で行われます。明確にするために、列のサイズは一貫していません。 1つのファイルがCOL4を13文字にし、別のファイルがCOL4を21文字の幅で持つことがあります。他のSOメンバーが述べたように厳密ではない。

+0

列は、各行の間に異なるオフセットから開始することができますか?例えば。行1は '| 1 2 3 | '(3スペース)、row2は' | 11111 2 3 | '(3桁も空白ですが、2行目の最初の値が非常に広いため、2行目はオフセット4が最初の行より大きくなります) – DVK

+0

いいえ、列サイジングは、ファイル。ファイルを区別できますが、ファイル内で一貫しています。 – Walinmichi

+0

列見出しが実際に表示されていますか? – Svante

答えて

2

あなたはこのような厳格な柱状のデータを扱っている場合は、unpackはあなたが何をしたい、おそらくです:

#!perl 

use strict; 
use warnings; 
use 5.010; 

use Data::Dumper; 

my $data = <<EOD; 
COL0 COL1 COL2 COL3   COL4 COL5 
    -  4 0.2  1  416489 463455 554 
      1 0.9  1   E1 
    0  3 1.4  14 E97-TEST 1 
    -  1 97.5 396   PASS Good 
EOD 

my @lines = split '\n', $data; 
for my $line (@lines) { 
    my @values = unpack("a5 A7 A7 A7 A13 A*", $line); 
    print Dumper \@values; 
} 

は、これはあなたが望むよう@values配列に自分の価値観をダンプするように見えるが、彼らは持っていますあなたがトリミングする必要がある先頭のスペース。

+0

**厳密な**カラムのデータではないかもしれませんが、ビットアンクローラ – DVK

+0

このメソッドをありがとう、それについては知りませんでした。しかし、私の課題のもう一つの部分は、列のサイズが変わる可能性があるということです。それで、私は3文字のトークンに焦点を当てることを考えていました。なぜなら、COL4は常に13文字幅であるとは限りません(COL4が13〜21文字のデータファイルを持つことができます)。 – Walinmichi

0

私はCanSpiceがすでに答えていることは知っていますが(もっと良い解決策かもしれませんが)、 "$ /"を使って入力区切り文字を設定できます。これはグローバル変数であるため、ローカルスコープ(おそらくサブ)で実行する必要があります。そうしないと、副作用が発生する可能性があります。例:

local $/ = " "; 
$input = <DATAIN>; # assuming DATAIN is the file-handler 

いいえ小さな正規表現を使用して空白をトリミングすることができます。例については、Wikipediaを参照してください。

1

私は2つのパスを使用します:最初に、各行にスペースを持つ文字列を探します。それらのインデックスで分割または展開します。空白のトリミングは後で行います。

あなたの例:列は、すべての空間である最後の行ショーで

COL0 COL1 COL2 COL3   COL4 COL5 
    -  4 0.2  1  416489 463455 554 
      1 0.9  1   E1 
    0  3 1.4  14 E97-TEST 1 
    -  1 97.5 396   PASS Good 

000011100001110000111000011100000000001110000000000 

1秒。

+0

したがって、列タイトルを使用してTEMPLATEを定義し、それらの値をUNPACKに渡しますか?私は今それを試みるつもりです。 – Walinmichi

+0

@Walinmichi:いいえ、_all_行を使用してテンプレートを定義します。 – Svante

+0

私は分かりません。ファイル全体には、これらのタイプのブロックが他にもたくさん含まれています。私は正しいブロックに私を得るコードがあります。私はブロックの終わりを知っています。なぜなら、各ブロックの下に "***** END *******"定数があるからです。 – Walinmichi

3

列の位置を把握する必要があります。実際にはかなり嫌なハックとして、あなたは全体のファイルを読み込むことができ、その後、一緒に文字列や行:

my @file = <file>; 
chomp @file; 

my $t = ""; 
$t |= $_ foreach(@file); 

$ tは、その列で常に空白文字があった場合にのみ列に空白文字が含まれます。他の列にはバイナリジャンクが含まれます。今、非空間にマッチするゼロ幅マッチでそれを分割:

my @cols = split /(?=[^ ]+)/, $t; 

私たちが実際にアンパック()フォーマットを生成するために幅の列のをしたい:

@cols = map length, @cols; 
my $format = join '', map "A$_", @cols; 

今のプロセスをファイル! :

​​3210

(このコードは軽くテストされている。)

+0

私のテキストブロックは実際には、多くのそのようなブロック(すべてが異なる列構造を持つ)を持つ大きなファイルのサブセットです。私は私のブロックの始めと終わりを知っていますが、どのようにシングルラインに入るのかわかりません...私はラインを連結することができますか? – Walinmichi

+0

私はこれを私のために働かせることができませんでした。私のPERLに関する知識が限られているため、どこにいたのか分からなかった。 Svanteとvmpstrの助けを借りてヘッダのタイトルが既知の定数であることに気がついたので、私は単純なsubstrを使ってしまいました。それを使って、私はすべての列の右端を見つけ出し、その間にスペースを入れました。いくつかのトリムで、私は動的な列の幅で私が望むものを得ることができました。私はこのタイプのソリューションが良いと確信していますが、PERLと同じように、私はこの問題を解決するために割り当てることができる短時間で私を困らせました。皆さんありがとう! – Walinmichi

関連する問題