正規表現、ループ処理の練習〜タブ区切りの.txtを.csvにする。
最初に、このお題の私の回答を見てくれた先輩の言葉。
● \ は、「エスケープに使用している」のか「そういう文字そのもの」なのか常に意識して考えなくてはならない。 ●dieが適切な部分に使えるかどうかで、どれくらいのperl使いなのか分かる。 ●プログラムは、他の人が読んだとき or 自分であとから読んだときに意図が分かりやすいように書かなければならない。 ●プログラムは、使用している言語の特性を生かした書き方をしなければならない。
では、以下から本題です。
準備物として、自分でタブ区切りの.txtファイルを作っておきましょう。以下、いきなり回答と解説です。
#! /usr/bin/perl use strict; use warnings; use Data::Dumper; open(FH,'<question.txt'); open(OUT,'>make.csv'); while(my $l = <FH>){ chop($l); my @array11 = split(/\t/,$l); ##データを作る## #txtファイルの中に、\nという文字(改行コードとは違う!)や \ という文字(エスケープにつかうバックスラッシュではない!)が含まれていたら、改行コードやエスケープ文字にしないように処理をしておく。 for(@array11){ $_ =~ s/\\(\\)|\\n/$1 || "\n"/eg; } #以下の様に1行で書くこともできる。if文や他のループを以下のように1行書きしているのであれば、合わせた方が他の人に分かりやすいかも。 #s/\\(\\)|\\n/$1 || "\n"/eg for @array11; #perlの特徴を生かしていない書き方 #$iや$jを意識せずに書くことができる=イテレーター #perlはイテレーター言語なので、使わないできない場合にのみ$iや$jを使用して書く。 #my $c = @array11; #foreach(my $i=0; $i<$c; $i++){ # $array11[$i] =~ s/\\(\\)|\\n/$1 || "\n"/eg; #} #$_を使うと元々のデータをいじることができるので、$iを使わずともできる。 ##CSVを作る## for(@array11){ $_ =~ s/"/""/eg; $_ = "\"$_\""; } ##データとCSVを同じfor分の中で回すのもありだが、意図をはっきりさせるために別のループにする。 ##読み込みファイル1行ごとに改行を入れつつファイルに書き出す## print OUT join (",",@array11),"\n"; ####解説#### ##データを作るときの正規表現の書き方(別解)## #これでもよい #s/\\(\\)|\\n/$1 || "\n"/eg for @array11; #以下のように2行でやろうとすると、お互いに影響を及ぼしてしまうためだめ。 #$l =~ s/\\n/\n/g; #$l =~ s(\\\\)(\\)g; #以下の=headから=cutの部分のようにする。 =head $l =~ s/(\\n|\\\\)/ if ($1 eq '\\n'){ "\n"; #改行は、""で囲まないと改行として機能しない。 }else{ '\\'; } /eg; #以下の様に1行で書くことも可能 # $1 || "\n" の部分は、$x = $y || 5; と同じ($yがあれば、$xに$yを代入する。$yが空なら、5を$xに代入する。)。 $l =~ s/\\(\\)|\\n/$1 || "\n"/eg; #よくやるやり方 #上記の $l =~ s/\\(\\)|\\n/$1 || "\n"/eg; の (\\)の部分が、何が来るかわからない or たくさんの種類がくる(\tなど。\tは、処理をしないとタブになってしまう。)場合、まず来る可能性のある物をハッシュ化しておく。>そして、正規表現でそのハッシュを使って置換。 my %esc = ( r => "\r", n => "\n", t => "\t", '\\' => '\\' ); $l =~ s/\\(.)/$esc{$1}/g; #(.)に想定していない物が来たらdieをするようにしておく #想定してないことが起こると思ったら、die $l =~ s/\\(.)/$esc{$1} || die $1/eg; #以下をやっておくとエンコードもデコードもしやすい #上記 %esc のキーと値を反転した物も%escにいれておく処理。 #%esc = (%esc, reverse %esc); =cut } close(FH); close(OUT);
このお題で、CSVファイルは扱いずらいと感じました。。。