はじめての親子ハイキングに挑戦!! >>

perlプログラム 外部複数ファイルの読み込み処理について

あるフォルダに T0001_05_01,T0001_05_02,T0001_05_03,…,T0001_05_31 という31個のファイルがあります。
それぞれのファイルは 下記のような 形式で記述されております。
(例 T0001_05_01のファイルの中身)
2010-05-01 00:00:00.000 N00001 AAAAAA
2010-05-01 00:00:00.108 N00018 BBBBBB
2010-05-01 00:00:10.305 N00002 AAAAAA
2010-05-01 01:00:10.966 N00008 CCCCCC

また、別のlist.txtに 下記のようなユニークなリストが入っております。
AAAAAA
CCCCCC
WWWWWW

このとき、list.txtの値が それぞれT0001_05_XXファイルの何行目に出力されているか
出力するperlプログラムを作成したい。
(出力結果イメージ:1ファイル化)
T0001_05_01 1行目 2010-05-01 00:00:00.000 N00001 AAAAAA
T0001_05_01 3行目 2010-05-01 00:00:10.305 N00002 AAAAAA

T0001_05_31 10行目 2010-05-31 03:00:00.999 N00400 AAAAAA
T0001_05_01 4行目 2010-05-01 00:00:00.000 N00008 CCCCCC

perlプログラム知識がないものなので、このようなファイルの出力の仕方がわかりません。
教えていただけると助かります。

A 回答 (3件)

サンプルプログラムを作成してみたので試してみてください。


テストしていないのでうまく行かないことがあるかも知れません。

use strict;
open FH, "list.txt" or die "Can't open list.txt: $!";
my @keyword = <FH>; chomp @keyword;
close FH;
my ($day, @result) = ('00');

while (++$day lt '32') {
my $file = "T0001_05_$day";
open FH, $file or die "Can't open $file: $!";
while (my $line = <FH>) {
foreach my $i (0 .. $#keyword) {
if ($line =~ /$keyword[$i]/) {
push @result, [$i, "$day", $., "$file ${.}行目 $line"];
last;
}
}
}
close FH;
}

@result = map { $_->[3] } sort { $a->[0] <=> $b->[0] || $a->[1] cmp $b->[1] || $a->[2] <=> $b->[2] } @result;

open OUT, ">out.txt" or die "Can't open out.txt: $!";
print OUT @result;
close OUT;
    • good
    • 0
この回答へのお礼

このプログラムで うまく解決できました。ありがとうございます。

お礼日時:2010/06/10 15:03

まだ解決しませんか?


もしLinux なら grepの方が楽かも。(windowsでは不可です)
以下を データT0001_05~ファイルとlist.txtと同じ場所において
パーミションを705にして実行してください。
------------------------------------- ○○.cgi
#!/usr/bin/perl
$| = 1;
print "Content-type: text/html\n\n";

@files = glob("T0001_05_*");
open(IN,"list.txt");@keys=<IN>;close(IN); chomp @keys;
foreach(@keys){
print "<b>$_</b><br>\n";
@result = `grep -n "$_" @files`;
foreach(@result){
split(/:/,$_,3);
print "@_[0] @_[1]行目 @_[2]<br>\n";
}
print "<hr>\n";
}
exit;
--------------------------------------
htmlで出してます。適宜ブラウザ上でコピーしてください。
    • good
    • 0
この回答へのお礼

ボリュームが多く何百万行もあるため、grep実行はすでに試みたのですが、処理時間がかかってしまいました。プログラム初心者のため このプログラム内容は今後の参考にさせていただきます。ありがとうございます。

お礼日時:2010/06/10 15:06

まず、それらのファイルが保存されているディレクトリを開く。


list.txtがあれば、それを開いてAAAAAなどのハッシュを作っておく。
ディレクトリにあるファイルの一覧を取得する。
それらを順番に開いて、そのファイルごとに一行ずつパターンマッチを行う。
AAA・・があれば、そのハッシュに、行数とその行のデータを配列で追加していく、
 配列のハッシュを作成する。
最後に、書き込み用ファイルを開いて書き込む。

たとえば、
$hash{'AAAAAA'}=[(T0001_05_01,1,2010-05-01 00:00:00.000 N00001),
         (T0001_05_01,3,2010-05-01 00:00:10.305 N00002)
             ]
とか、メモリーを消費するのでSEDなどストリームエディタを使うほうが早くて良いのだろうけど・・。
    • good
    • 0
この回答へのお礼

処理速度がなかなか改善できず、この処理では数日処理でも完了しませんでした。やり方は今後の参考にさせていただきます。

お礼日時:2010/06/10 15:07

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Q複数ファイルの読み込みについて

perl初心者です。

あるディレクトリから拡張子がdataであるファイルを全て読み込みたいのですが、方法がわかりません。
cshで書くと
foreach arg (*.data)
コマンド $arg

のようになりますが、perlだと
foreach $arg (@arg){
コマンド $arg

となりますよね?
引数がリストなのでよくわかりません。
そもそもperlではできないのでしょうか?


それともう一点ですが、ファイルオープンするときに
foreachループの中で
open(FILE, "$arg");
とすることは可能ですか?
上の質問と組み合わせて全てのファイルを開いて作業を行いたいので。

説明が下手ですいません。補足しますのでよろしくお願いします。

Aベストアンサー

while(<*.data>)
{
## $_には、*.DATAなファイル名が格納されている。
open(F,"$_"); ##openする。
while(<F>)
{
##読み出された内容が$_に格納されている。
print $_; ##出力してみる。
}
}

というのが最短コーディングです。

Q一つのテキストファイルと複数のファイルの結合

よろしくお願いします.ディレクトリ内の一つのテキストファイル(joint.txt)と複数のファイルの結合を行ごとに隣へ結合するプログラムを作成しています.ここで以下のプログラムを作成したのですが,うまくいかないため,誤っている部分をご指摘願えないでしょうか.



my $dirname = '.';

opendir(DIR, $dirname) or die "$dirname: $!";

while (my $dir = readdir(DIR)) {

next unless (-f $dir);
next unless ($dir =~ /\.txt$/);

open(FILE, $dir) or die "$dir: $!";
open(FILE2,"joint.txt");

my @file = <FILE>;
my @file2 = <FILE2>;
close(FILE);
close(FILE2);
foreach my $line (@file) {
foreach my $line2 (@file2) {
chomp $line2;
$line = "$line2.",".$line";
}
}
open(NEWFILE, "> $dir") or die "$dir: $!";

print NEWFILE @file;
print NEWFILE @file2;
close(NEWFILE);
}
closedir(DIR);

よろしくお願いします.ディレクトリ内の一つのテキストファイル(joint.txt)と複数のファイルの結合を行ごとに隣へ結合するプログラムを作成しています.ここで以下のプログラムを作成したのですが,うまくいかないため,誤っている部分をご指摘願えないでしょうか.



my $dirname = '.';

opendir(DIR, $dirname) or die "$dirname: $!";

while (my $dir = readdir(DIR)) {

next unless (-f $dir);
next unless ($dir =~ /\.txt$/);

open(FILE, $dir) or die "$dir: $!";
open(FILE2,"joint.t...続きを読む

Aベストアンサー

>>No.3
> 早速実行してみたところ,最初のファイルは思ったように処理される
> のですが,2つ目のファイル以降は処理されたファイルが前回の
> ファイルの内容を引き継ぎ,その後に出力されてしまいます.
> 具体的には以下の内容です.

結局修正してみました。
以下のような感じです。

use File::Basename;

my $dirname = '.';

die('not open : joint.txt') unless(open(FILE, 'joint.txt'));
my $file = join('', <FILE>);
close(FILE);

while(<$dirname/*.txt>) {
my $fn = (fileparse($_))[0];
next if($fn eq 'joint.txt');
my @file = split(/\n/, $file);
if(open(FILE, $_)) {
my @file2 = <FILE>;
for(my $i = 0; $i <= $#file2; $i++) {
$file[$i] .= ",$file2[$i]";
}
close(FILE);
if(open(FILE, ">$_")) {
print FILE @file;
close(FILE);
}
}
}

あと、今回の場合は関係ないのですがNo.2とNo.3で提示されたイメージ
内容が逆のような気がするのですが。(^_^;
例外的なことは殆ど考えていないので実際にはいろいろ修正する必要が
出てくると思いますけど、そこまで考慮できなくてすみません。

>>No.3
> 早速実行してみたところ,最初のファイルは思ったように処理される
> のですが,2つ目のファイル以降は処理されたファイルが前回の
> ファイルの内容を引き継ぎ,その後に出力されてしまいます.
> 具体的には以下の内容です.

結局修正してみました。
以下のような感じです。

use File::Basename;

my $dirname = '.';

die('not open : joint.txt') unless(open(FILE, 'joint.txt'));
my $file = join('', <FILE>);
close(FILE);

while(<$dirname/*.txt>) {
my $fn = (fileparse...続きを読む

Q複数のCSVファイルを一つのCSVファイルに

ディレクトリ内に複数あるCSVファイルを一つのCSVにまとめたいのですが、方法がわからないので教えて下さい。
ファイルの読み出しと追加書き込みを繰り返せば良いとは思っています。
ディレクトリ内のファイルを検索するところまでは出来ました。

Aベストアンサー

  my $path = "./data";  #csvのあるディレクトリ
  opendir(DIR, $path) || die "Error!!";
  my @dirs = grep /\.csv$/i, readdir(DIR);
  closedir(DIR);

  if(open(OUT,">./mix.csv")){
    for my $fname (sort @dirs){
      if(open(IN,"$path/$fname")){
        my @lines = <IN>;
        print OUT @lines;
        close(IN);
      }
    }
    close(OUT);
  }

#ファイルを順に読み込んで書き込んでいるだけです。テキトウに改造してみてください。
#動作確認はしてないです。
#または、perlから、OSのコピーコマンドを呼んでファイルを結合してもいいと思います。

Qファイルからデータを読み込んで、配列に格納する方法

データファイル grep.dat があり、その中は
12345
67890
ABCDE
(EOF)
となっています。
 
このファイルの中身を読み込んで、配列 P[0]の
中に("12345","67890","ABCDE") に格納したい
のですが、どのように記述すればよいでしょうか。

Aベストアンサー

多次元配列に代入する場合

my @p;
open FILE, "grep.dat";
  @{$p[0]} = <FILE>;  ・・(a)
close FILE;

openの書式などは好みで変えてください。
結論を言えば、(a)のように書けばokです。

#細かい書式は他にもありますので調べてみるといいかもしれません。

QPerlで別ファイルから文字列の抽出

当方、サーバ管理でインフラ系の経験しかなく、今回はperlでスクリプトの作成に挑戦しておりますがなかなか理解できていません。お知恵をお貸しください。

やりたいこと:
ある入力を受けたら、別ファイルに照会して特定列の文字列を抽出する。以下に例を示します。

入力が gad の場合(小文字です)、file1を参照する。例では一行目にGAD****があるのでこれに該当することとする。最終的にoffice が出力されるようにしたい。


file1の内容:
GAD93911 <test1> office
HOA14845 <test2> desk
ABC52311 <test3> chair
KFI33823 <test4> home

よろしくお願いいたします。

Aベストアンサー

ファイルを開いて、各行を順番に /$in\d+\s<\w+>\s(\w+)/iでマッチするものを取り出して、それを使う・・


人気Q&Aランキング