• ベストアンサー

ファイルからのデータ読み込みとデータ処理

ActivePerlをインストールしたばかりの初心者です。 ファイルからデータを読み、データ処理をするプログラムをつくっている所ですが 、データファイルの読み込み後の処理がうまくいきません。 データ処理では、空白文字、マイナスの符号も含めて3個ずつで一つの数値とします。 $a ='-10 -1 0 22177'; @foo = split( /(\s\s\d|\s\d\d|\d{3}|-\d{2}|\s-\d{1})/, $a) ; print "@foo\n"; 【出力結果】 -10 -1 0 22 177 ファイルから1行ずつデータを読み込み、同様の処理を行う以下のプログラムですが、正しくファイルが表示された後は止まってしまいます。 どこで躓いているのかご教示下さい。 #プログラム $no = 1; while ($line = <>) { print $no, "\t", $line; print $line; ++$no; } while ($line = <>) { @foo = split( /(\s\s\d|\s\d\d|\d{3}|-\d{2}|\s-\d{1})/, $a) ; print "@foo\n"; }

  • Perl
  • 回答数6
  • ありがとう数4

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

ファイルを標準入力に流し込んで動かしているのだと思いますが、ファイルの終わりを読み込んだとき1つ目のループを抜け、もう1つのループが標準入力からの入力待ちになって止まったように見えます。2回目のループにはファイルの内容は流し込まれません。 while(<>){処理} を2回やるのではなく、 @line=<>; と一度配列によみこんでから、 foreach (@line){処理} を2回やるように変更するのが1つの手だと思います。 なお、splitの仕方がそれでよいのかはふめいです。 すくなくともwhileの中の$aは未定義ですね。

perl001
質問者

お礼

なるほど、foreachを使うと一行ずつ読み込み処理できました。 foreach ( @lines=<> ) { @foo = split( /(\s\s\d|\s\d\d|\d{3}|-\d{2}|\s-\d{1})/) ; print "@foo\n"; } ありがとうございました。 早く尋ねれば良かった~

その他の回答 (5)

回答No.6

空白が入るのが嫌なら。。。 $str = " -2 9 22 36 42 45 49 52 49 45"; @list=map{s/ //g;$_}($str =~ /.{3}/g); print "@list\n"; とか。

perl001
質問者

お礼

もう完璧です。 プログラムを提示して頂き、大変参考になりました。 最後までおつきあい頂きありがとうございました。

回答No.5

>空白を@で表すならば、 @-2@@9@22@36@42@45@49@52@49@45 ルールは、空白文字と符号を含めデータを3つずつに区切る、です。 それなら $str = " -2 9 22 36 42 45 49 52 49 45"; $str =~ s/(.{3})/push(@list,$1)/eg; print "@list\n"; こんなんでどうでしょ?

perl001
質問者

お礼

スマートです!勉強になりました。 ありがとうございました。

回答No.4

データの数値には、負の整数2桁、負の整数1桁、1桁から3桁までの負でない整数があります。 ファイルデータは以下のようになっています。 -2 9 22 36 42 45 49 52 49 45 -11999777777777777777777777777 ↓ -2,9,22,36,42,45,49,52,49,45 -11,999,777,777,777,777,777,777,777,777 ファイルを読み込み上記のように変換する処理を行いたいのです。 これだけでは、ルールとしてあいまいです。 >負の整数2桁、負の整数1桁、1桁から3桁までの負でない整数があります。 の情報だけでは、 -11999777777777777777777777777 が、 -1,199,9,77,777,7,77,777, とか -11,99,9,77,7,77,7,77,777, とか、いくらでも別け方が有るなかで -11,999,777,777,777,777,777,777,777,777 なるのかの理由がわかりません。 また、 -2 9 22 36 42 45 49 52 49 45 ↓ -2,9,22,36,42,45,49,52,49,45 が言うのは、空白があればそれを区切りとして扱うということですか? なら、 -2 9 2236 42 45 49 52 49 45 のように、空白も含むけれど4つ以上の数字が続く場合は?、また、 -2 9 2236 -42454952495 なら? とにかく、ルールを一意的に解釈できるようにしたほうが適切な解答もらえると思いますよ。

perl001
質問者

補足

例が誤っていました。すみません。 空白を@で表すならば、 @-2@@9@22@36@42@45@49@52@49@45 ルールは、空白文字と符号を含めデータを3つずつに区切る、です。 -11999777777777777777777777777 は頭から区切っていくと -11,999,777,777,777,777,777,777,777,777 となります。 数字だけを3桁ずつに区切るならば http://oshiete1.goo.ne.jp/kotaeru.php3?q=1034162 なのですが、空白文字とマイナスが入っているので下手なプログラムを作っています。

  • SE-1
  • ベストアンサー率57% (26/45)
回答No.3

# 余計なお世話かもしれません・・・ # #2 さんのプログラムを実行すると分かりますが、@foo には空の要素が幾つか入ります。 # split 内の式を見て perl001 さんの得たい配列を勝手に想像して以下を書いてみました。 foreach (my @lines=<DATA>){ my @foo2; foreach (my @foo = split(/\s/,$_)){ $_=~/\d{4,}/ ? push @foo2, $_=~/(-??\d{2})(\d{1,3})/ : push @foo2, $_; } print "$_|" foreach @foo2; print "\n"; } __DATA__ -10 -1 0 22177 25 -98 5 -77364

perl001
質問者

補足

プログラムありがとうございます。 データについて加筆します。 データの数値には、負の整数2桁、負の整数1桁、1桁から3桁までの負でない整数があります。 ファイルデータは以下のようになっています。 -2 9 22 36 42 45 49 52 49 45 -11999777777777777777777777777 ↓ -2,9,22,36,42,45,49,52,49,45 -11,999,777,777,777,777,777,777,777,777 ファイルを読み込み上記のように変換する処理を行いたいのです。

回答No.2

#1さんの言われるような方法か、 または pushを使います $no = 1; while (<>) {push @_,$_; print $no . "\t". $_; ++$no; } foreach(@_) {@foo = split( /(\s\s\d|\s\d\d|\d{3}|-\d{2}|\s-\d{1})/) ; print (join '|',@foo)."\n";# テスト用に | を入れて出力してみる } ##私も splitの中の式は検証していません

perl001
質問者

お礼

#3さんがご指摘のように、空要素が入りますが、今の私にはその理由がわかりません。 おいおい勉強していきます。 貴重なお時間を割いて回答して頂き、ありがとうございました。

関連するQ&A

  • 繰り返し処理の使い方

    繰り返し処理の使い方について質問です。以下の.plファイルを作成しました。 for($line =0;$_ =<stdin>;$line++){ if($line < 400){ @line = split/,/,; $data1 +=$line[1]; } } for($line =0;$_ =<stdin>;$line++){ if($line < 800){ @line = split/,/,; $data2 +=$line[1]; } } $data_1 = $data1; $data_2= $data2; print"$data_1 \n"; print"$data_2 \n"; この.plファイルで合計計算の実行を試みたのですが、data_2の値が0でした。(data_1は合計計算が出来ています。) 繰り返し処理の2つ目はなぜ0なのでしょうか、またdata_2の合計計算を実行するにはどうすれば良いのでしょうか。 お願いします。

    • ベストアンサー
    • Perl
  • 行指向処理でデータの読み込みについて(@_)

    perl初心者です。 ファイルからデータを読み込んで3列目の要素を取り出すプログラムを作ろうと思っています。 その途中の勉強段階で参考書に $,=','; $\="\n"; @ARRAY=(); while(<>){ chop; split; @ARRAY=(@ARRAY, [@_] ); } print @ARRAY; foreach (@ARRAY){ print @$_; } print $ARRAY[1][2]; というプログラムがありました。このプログラムの大まかな意味は理解できます。 しかし、読み込ませるファイルを 1 2 3 4 5 6 7 8 9 のようにして コマンドプロンプトで実行してみると ARRAY(0x198b9c),ARRAY(0x198998),ARRAY(0x19a830) となり、参考書で紹介される結果の ARRAY(0x198b9c),ARRAY(0x198998),ARRAY(0x19a830) 1,2,3 4,5,6 7,8,9 6; となりませんでした。色々調べたんですが、どうやら print @_; に反応(?)してくれてないみたいです。 私の使用しているPCはwindows7です。原因がわからず先に進めない状況です。指導お願い致します。

    • ベストアンサー
    • Perl
  • ファイルからの読み込み

    fscanfを使ってファイルの中身を読み込みたいのですが、ファイルの中身の長さが統一されていない場合どうしたらよいでしょうか? 読み込むファイルの中身 A d 1 B 3 2 G 5 1 2 B 6 G H 5 2 5 今まではファイルの中身の各行の文字数が全部3つだったので fp=fopen(A.txt,"r"); while(fscanf(fp,"%s %s %s",data,data+1,data+2)!=EOF) { printf("%s?n",data); }としていました。わかりにくい文章ですいません。

  • Perlで2つのテキストファイルの処理する方法

    めぐみです。 tatsu99さま、以下のプログラムを親切にアドバイス頂きまして本当にありがとうございました。 追記で質問させて頂きたいことがあります。 --------------------------------------------------------------- $file_a = shift(@ARGV); $file_b = shift(@ARGV); open FHA,$file_a or die("can't open $file_a"); @data_a = (); while($line=<FHA>){ chomp($line); push @data_a,$line } close FHA; open FHB,$file_b or die("can't open $file_b"); @data_b = (); while($line=<FHB>){ chomp($line); push @data_b,$line } close FHB; foreach $da (@data_a){ printf("%s%d%d%d\n",$da,$data_b[0],$data_b[1],$data_b[2]); printf("%s%d\n",$da,$data_b[0]); printf("%s%d%d\n",$da,$data_b[1],$data_b[2]); printf("%s\n",$da); printf("%s%04d%02d%02d\n",$da,$data_b[0],$data_b[1],$data_b[2]); printf("%s%02d%02d\n", $da,$data_b[1],$data_b[2]); printf("%d%d%d%s\n",$data_b[0],$data_b[1],$data_b[2],$da); printf("%d%s\n",$data_b[0],$da); printf("%d%d%s\n",$data_b[1],$data_b[2],$da); printf("%s\n",$da); printf("%04d%02d%02d%s\n",$data_b[0],$data_b[1],$data_b[2],$da); printf("%02d%02d%s\n",$data_b[1],$data_b[2],$da); }--------------------------------------------------------- 下記のような内容を追加で出力させることは難しいでしょうか。 1.B.txtを元に下記のように数字だけのデータも追加で出力させたかったです(1行目1986,2行目3,3行目6の場合) 198636 1986 36 19860306 0306 2.A.txtを元にA.txtから下記の内容も追加で出力させたかったです(4行目以降は無視して構いません)。 1行目と2行目 2行目と3行目 3行目と1行目 2行目と1行目 1行目と3行目 3行目と2行目 以上、何卒よろしくお願いいたします。

  • データの入れ替え処理が巧くできないのですが

    いつもお世話になります 簡単なDBを作っているのですが、データの更新処理が巧くいかなくててこずっています POSTメッソドで送られてきた name=actionの内容がedit2、の時 sub menteが実行されます同じく name=noの変数には更新したいファイルの番号がセットされます それらを取得して、ファイルを開き $nooの内容(DBのファイル番号)とnoが一致したらブラウザから送られてきたデータと その部分のデータ($nooはデータの先頭で以降<>で区切って変数が格納される) を入れ替える処理を行いたいのですがどの様に書いたらいいのでしょうか、下記のコードですと変数 $_に更新される前のデータしか代入できず結果ファイルの入れ替えは行えません open(IN,"$logfile") || &error("Open Error : $logfile"); while (<IN>) { ($noo,@arg_[0..$#eqipument],@p[0..5],$n_article,$w_article,@reselect_marks) = split /<>/; if ($no == $noo ) { $_ = join('<>',$noo,(map{$arg_[$_]}(0..$#eqipument)),$p0,$p1,$p2,$p3,$p4,$p5,$n_article,$w_article,@reselect_marks,),'<>',"\n"; } push(@new,$_); } close(IN); # 更新 open(OUT,">$logfile") || &error("Write Error : $logfile"); print OUT @new; close(OUT); 尚ブラウザから送信されてくるデータは以下のような感じです print qq|<form action=\"$myself\" method=\"POST\">\n|; print qq|<input type=hidden name=mode value=\"admin\">\n|; print qq|<input type=hidden name=action value=\"edit2\">\n|; print qq|<input type=hidden name=no value=\"$no\">\n|; 宜しく御教授お願いいたします。

    • ベストアンサー
    • Perl
  • Excelのcsv形式の読み込み

    Excelのcsv形式の読み込み 前回、http://okwave.jp/qa/q6018540.htmlで 質問させていただきましたJurassic_periodです。 お力を貸していただきました方々本当にありがとうございました。 今回ですが同じプログラムでまた壁にぶつかってしまいました。 どうかよろしくお願いいたします。 Excelのcsv形式の「file.csv」のようなデータを読み込んでいます。 「out.csv」のように出力したいのですが 未入力「""」のデータ箇所が多々ある事に気が付きました。 次データを読み込むため出力データがズレてしまい困っています。 「file.csv」 "2010/1/1","C","こんにちは","田中","end", "2009/10/2","B","おはよう","","end", "2007/3/20","E","Good mor ning","佐藤","end", "1988/8/16","","こんばんは","中 村","end", "","A","Hello","木村","end", "2005/9/17","D","おはようご ざいます","斎藤","end", 「out.csv」(このように出力したいです) C,こんにちは,田中,2010/1/1,end, B,おはよう, ,2009/10/2,end, E,Good morning,佐藤,2007/3/20,end, ,こんばんは,中村,1988/8/16,end, A,Hello,木村, ,end, D,おはようございます,斎藤,2005/9/17,end, 解決法として、正規表現を用いて「半角スペース」を入れようとしました。 また、直接「file.csv」の「,"",」を置換で「," ",」にしましたが 基データを操作するのは好ましくないのでプログラムで どうにか処理ができないでしょうか。 「今書いているプログラムです」 #!/usr/local/bin/perl use strict; use Fatal qw/ open /; my $csv_file = "file.csv"; my @csv; &readCsvFile($csv_file); open(OUT,">out.csv"); for(my $i=0; $i<=$#csv; $i++){ $csv[$i][0] =~ s/"//; #行頭の"を削除 $csv[$i][4] =~ s/"//; #行末の"を削除 $csv[$i][0] =~ s// /; #空データを半角スペースに置換 $csv[$i][1] =~ s// /; $csv[$i][3] =~ s// /; print OUT $csv[$i][1],","; print OUT $csv[$i][2],","; print OUT $csv[$i][3],","; print OUT $csv[$i][0],","; print OUT $csv[$i][4],",\n"; } close(OUT); sub readCsvFile { open(IN, $_[0]); my $line = ""; while(<IN>) { chomp; $line .= $_; next if $line !~ /end/; push @csv, [ grep { length } split(/","|",|"/, $line) ]; $line = ""; } close(IN); } どうか、よろしくお願いいたします。

    • ベストアンサー
    • Perl
  • PHPのファイルの読み方のコード

    下記はpearlのファイルの読み込みです #!/usr/local/bin/perl print "Content-type: text/html\n"; print "\n"; require './jcode.pl'; if (!open(IN,"$userfile")) { &error("投稿データファイルを開けません"); } @DATA = <IN>; @DATA = reverse(@DATA); close(IN); foreach $line (@DATA){ ($f1,$f2,$f3) = split(/,/, $line); &jcode'convert(*line,'sjis'); push(@CS,$line); } foreach (1.. 100) { ($f1,$f2,$f3) = split(/,/, $CS[$_]); print "$f1\n"; } exit; ############################################## foreach (1.. 100) { ($f1,$f2,$f3) = split(/,/, $CS[$_]); print "$f1\n"; } この部分のPHPのコ-ド書き方をお願いします

    • ベストアンサー
    • PHP
  • ディレクトリ内のテキストファイルに対する同一処理

    よろしくお願いします。現在Linuxの環境でテキスト処理をしております。 ディレクトリ内にファイル名の異なった以下のような大量ファイルがあります。 a.txt 0,1,2,3,4,5,6,7 1,2,3,4,5,6,7,8 b.txt 2,3,4,5,6,7,8,9 3,4,5,6,7,8,9,10 これらのファイルをカンマでsplitし、左から2番目の数にだけ1を引き,下のディレクトリであるoutに出力させます。出力は以下のようになります。 ./out/a.txt 0,0,2,3,4,5,6,7 1,2,3,4,5,6,7,8 ./out/b.txt 2,2,4,5,6,7,8,9 3,4,5,6,7,8,9,10 そこで以下のようなPerlのプログラムを作成しました。 use strict; use warnings; my $dirname = '.'; opendir(DIR, $dirname) or die "$dirname: $!"; while (my $dir = readdir(DIR)) { next unless (-f $dir); next unless ($dir =~ /\.txt$/); print $dir, "\n"; open(FILE, $dir) or die "$dir: $!"; my @file = <FILE>; foreach $line (@file) { my ($a,$b,$c,$d,$e,$f,$g,$h) = split(/,/, $line);      my $b = $b - 1; close(FILE); } open(NEWFILE, "> ./out/$dir") or die "$dir: $!"; print NEWFILE @file; close(NEWFILE); } closedir(DIR); ですが、出力は完了するのですが、元のファイルから計算がされていません。どこがどう間違えているのかご指摘よろしくお願い申し上げます。

    • ベストアンサー
    • Perl
  • データの読み込みがうまくいかなくて、困っています

    プログラミング初心者です。 誤差逆伝播学習のプログラムを行っています。 C言語で、データの読み込み部分がうまくいかなくて、困っています。 borland , BCC Developerなどを用いてやっております。 やりたいことは、テキストファイルから数字を読み込み、それを行列に格納してデータとして送るということです。 その際に、テキストファイルで行と列で表示されたものを送ろうと考えています。30×30の、1と0で表示された絵と教師信号を読み取っています。 列だけの読み込みは正常に動いたのですが、行と列で表示されたものの読み込みができません。char型で変数を宣言しているので、数字として読み込めていないとか、そういったことがあるのでしょうか。o1[][],t[][]の部分に正しく値が送れるようにしたいです。 非常にわかりにくくて申し訳ないのですが、お分かりになる方がいたら、どこをどう変えれば良いか、教えて頂きたいです。 「間違っている列と行の読み込み」 //データをファイルから読み込む// void read_file(name) char *name; { int i,j,k; //ループカウンター// FILE *fp; //ファイルポインタ// char buff[MCHS]; //buffの最大文字数1024 //ファイルオープン// if((fp=fopen(name,"r"))==NULL){ fprintf(stderr,"%s:File open error !!\n",name); exit(-1); } //学習データを読み込む// fscanf(fp, "%d",&learning_pattern_no); //学習パターンの数読み込み fscanf(fp,"%d",&test_pattern_no); //テストパターンの数読み込み printf("学習パターンの数:%d\n",learning_pattern_no); //学習パターンの数表示 printf("テストパターンの数:%d\n",test_pattern_no); //テストパターンの数表示 i=0;j=0; while( fgets( buff, MCHS, fp ) != NULL ){ if(j<=learning_pattern_no+test_pattern_no-1){ for( k=0; k<MCHS; k++ ){ o1[j][i+k]=buff[k]; //o1[j][i+k]にbuff[k]を入れる printf("%c",buff[k]); //printfで確認 if( buff[k] =='\n'){ i=i+k; if (i==InputUnitNo){ i=0; j++; printf("%d",j); }//if(i==InputUnitNo)終了 break; }//if(buff[k])終了 }//for終了 }//if(j<=learn+test)終了 else{ //ここから教師信号の読み取り for( k=0; k<MCHS; k++ ){ t[i][k]=buff[k]; printf("%c",buff[k]); //教師信号の確認 if( buff[k] == '\n' ){ i++; break; }//if(buff[k])終了 }//for終了 }//else終了 }//while終了 } 「正常に動いた列だけの読み込み」 //データをファイルから読み込む// void read_file(name) char *name; { int i,j; //ループカウンター// FILE *fp; //ファイルポインタ// //ファイルオープン// if((fp=fopen(name,"r"))==NULL){ fprintf(stderr,"%s:File open error !!\n",name); exit(-1); } //学習データを読み込む// fscanf(fp, "%d",&learning_pattern_no); printf("学習データの数:%d\n",learning_pattern_no); for(i=0;i<learning_pattern_no; i++){ for(j=0;j<InputUnitNo; j++) fscanf(fp,"%lf",&o1[i][j]); for(j=0;j<OutputUnitNo; j++) fscanf(fp,"%lf",&t[i][j]); //教師信号 } //テストデータを読み込む// fscanf(fp,"%d",&test_pattern_no); printf("テストデータの数:%d\n",test_pattern_no); for(i=learning_pattern_no;i<learning_pattern_no+test_pattern_no;i++) for(j=0;j<InputUnitNo;j++) fscanf(fp,"%lf",&o1[i][j]); fclose(fp); }

  • logファイルをひらいての処理の仕方を教えてください。

    データベース検索のperlをカスタマイズ中です。 ユーザが入力したものを、検索条件のひとつにしたいのですが、表示されません。 インプットしたものはlogファイルに書き込まれるので、それを開いて反映させればいいのだろうということまでは、なんとかわかるのですが、どのように表記していいのか・・・今はない知恵を絞ってこのように表記しているのですが。 if (!open(FD,"$logfile")) { &error(0); } @lines = <FD>; $cnt = @lines; close(FD); print "<select name=P2 >\n"; print "<option value=\"0\" selected>指定なし\n"; $i =0; foreach $line (@lines) { ($no,$sub,$com1,$com2,$com3,$p1,$p2,$p3,$p4) = split(/\,/,$line); chop; if ($p2 ne '') { $i++; $p2s{($p2)[0]}++; $n++; } } foreach (keys %p2s) { print "<option value=\"$_\">$_\n"; } print "</select></td>\n";

専門家に質問してみよう