• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:ファイルの読み込みと出力)

ファイルの読み込みと出力プログラム作成

このQ&Aのポイント
  • Perl初心者のため、ファイルの読み込みと出力を行うプログラムを作成しています。しかし、ファイル内の改行がうまく処理できずに困っています。
  • ファイル.csvを読み込んで、out.csvに出力するプログラムを作成中です。ファイル内には不要な改行が混ざっているため、正しく出力できません。
  • Perlの初心者で、ファイル.csvを読み込んで出力するプログラムを作成していますが、改行の処理につまずいています。お力をお借りしたく思います。

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

  • ベストアンサー
  • kumoz
  • ベストアンサー率64% (120/185)
回答No.2

気づいた点を直してみましたので、参考にしてください。なお、ソースデータにクォートされた二重引用符がないことが条件になります。 #!/usr/local/bin/perl use strict; use Fatal qw/ open /; my $csv_file = "file.csv"; # my @csv = &readCsvFile($csv_file); # 代入は必要ない my @csv; &readCsvFile($csv_file); open(OUT,">out.csv"); # for(my $i=0; $i<=5; $i++){ for(my $i=0; $i<=$#csv; $i++){ # 配列の要素数に合わせる    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],","; # 改行が必要    print OUT $csv[$i][4],",\n"; } close(OUT); sub readCsvFile { #   open(DATA, $_[0]); # DATA には特別な意味があるので好ましくない    open(IN, $_[0]);    my $line = "";    while(<IN>) {      chomp;      $line .= $_;      next if $line !~ /end/; #     push @csv, [ split(/",\"/) ];      push @csv, [ grep { length } split(/","|",|"/, $line) ]; # "," のみでは行頭や行末の " が残る      $line = "";    }    close(IN); #  return @csv; }

Jurassic_period
質問者

お礼

回答していただきありがとうございました。 無事に解決できました! 要所々にコメントをいれていただきとても分り易かったです。 こうした問題をすぐに解決できるようにもっと勉強します。 ありがとうございました。

その他の回答 (2)

  • ralf124c
  • ベストアンサー率52% (232/446)
回答No.3

こんな感じでどうでしょうか? 条件としてご質問欄のようにデータは  ・CSVはExcelのCSV形式(セル内に改行や記号が含まれる)  ・データもプログラムもshift-jisコード(正規表現が誤動作する可能性があるのでEUCとかでやった方が・・・) ただし「""」内のデータに「,」が含まれていると出力されたデータが再利用時に使い物にならない(別の文字に変換要)ので要注意 -------------------------------------------------------------------------------- #!/usr/local/bin/perl use strict; my $csv_file = "file.csv"; my @aDT = &readCsvFile($csv_file); ## CSVファイルの読み込み map { s/\r\n|\r|\n//g } @aDT; ## 行内の改行を削除する open(WR_DATA,">out.csv"); map { print WR_DATA $_."\n"; } @aDT; ## 最近mapにはまってまして・・・「foreach(@aDT){ print WR_DATA $_."\n"; }」と同じです close(WR_DATA); exit; sub readCsvFile { my $sFN = shift; my @aCSV; open(RD_DATA, $sFN); while(my $line = <RD_DATA>){ $line .= <RD_DATA> while ($line =~ tr/"// % 2 and !eof(RD_DATA)); $line =~ s/(?:\x0D\x0A|[\x0D\x0A])?$/,/; my @aDT = map {/^"(.*)"$/s ? scalar($_ = $1, s/""/"/g, $_) : $_} ($line =~ /("[^"]*(?:""[^"]*)*"|[^,]*),/g); ## ? ## 元来この@aDTに各行の要素がいったん格納されますので個別に処理したいならここに処理を記述 my $sTmp = join(",",@aDT); ## 各要素をコンマ区切りで結合して一行分を生成する push(@aCSV,$sTmp); } close(RD_DATA); return @aCSV; } -------------------------------------------------------------------------------- 経験上の突っ込みどころとしては  ・perlは行指向の言語なので多次元配列は避けるのが吉(やっていけないわけじゃないけど・・・)  ・局所変数はしっかり定義(関数内の@csvは要注意)  ・ファイルハンドル名や変数は、できるだけ予約語や組み込み関数名に類似した名前はさける

Jurassic_period
質問者

お礼

ご回答いただき、ありがとうございました。 > CSVはExcelのCSV形式(セル内に改行や記号が含まれる) 説明不足で申し訳ございませんでした。 ExcelのCSV形式のため変に改行が入ってしまい四苦八苦していました。 ちなみにデータとプログラムですがEUCで行っています。 > ただし「""」内のデータに「,」が含まれていると出力されたデータが > 再利用時に使い物にならない(別の文字に変換要)ので要注意 まさにその通りです! データ内に「,」がたくさん入っているため別の文字に変換をして処理をしていました。 mapの使い方に目から鱗です! とても参考になります! また、経験に基づいたアドバイスもとても参考になりました。 Perlをもっと勉強しないといけないと思いました。 本当にありがとうございました。

回答No.1

Perlの細かい文法は忘れてしまいましたので、 おおまかなアルゴリズムを書きます。 readCsvFile の中で、 <DATA>行が「end」文字列で終わってなければ、 次行を現在の行末に連結し、得られた行が「end」で終わるまで同じことを繰り返す。 得られた行が「end」で終わっていればその行を @csv に push。 これで希望の結果が得られると思います。

Jurassic_period
質問者

お礼

アルゴリズムの回答、ありがとうございました。 参考にさせていただきます。

関連するQ&A