値を置換したいのですが、Perlは初めてで全然わかりません。
項目はタブ区切りで以下のようになっています。
このデータから誕生月が1桁の場合は"09"、性別は男なら"1"、女なら"2"としたいのです。
(test.csvの中身)
年月日 氏名 誕生月 誕生日 性別
060904 日本太郎 10 4 男性
060904 日本花子 9 4 女性
どなたか助けてください。
プログラムは人のを見て理解するのが上達の早道と思います。
割と定番サイトですが、perlの関数や書式、演算子などは、
以下がわかりやすいと思います。
http://pzxa85.hp.infoseek.co.jp/www/wwwperl.htm
ご提示の例ですと以下のようなプログラムでいけると思います。
後はデータの形式などにあわせて、
多少改良するといけると思います(動作確認済みです)。
中にコメントも入れておきましたので参考にしてください。
######################################################################
# 前提
#
# 入力データは以下の形式とする。
# 但し、5カラム目以降も、任意のデータがあった場合でもそのまま格納できる。
#
# 060904 日本太郎 10 4 男性
# 060904 日本花子 9 4 女性
#
# 1データ一行で、区切り文字はタブ1つのみ
# 性別は 4 カラム目にあるとする(0から数えて4カラム目)
# 0カラム目:年月日
# 1カラム目:氏名
# 2カラム目:誕生月
# 3カラム目:誕生日
# 4カラム目:性別
######################################################################
######################################################################
# 以下、条件に合わせて書き換える
# 入力ファイル名を以下に指定。
$in_file = "in.txt";
# 入力ファイル名を以下に指定。
$out_file = "out.txt";
# 性別が4カラム目にある場合は4を指定。
$num = 4;
######################################################################
# 前提が変わらない場合はこれ以降の変更は不要。
#
# 入力ファイルをオープン
open(IN, "$in_file") || die "Can't open file [$in_file].";
# 置換した後のデータを入れる為の変数を初期化
$out_data="";
# ループ処理で全ての行にわたって処理
while (<IN>) {
# 行末に改行文字があれば削除
chomp;
# 1行のデータをタブで区切られた項目ごとに変数に格納
# 以下の例では、
# $data[0] に0カラム目
# $data[1] に1カラム目
# というように格納される
@data = split(/\t/);
# カラム毎に処理を行う
# $#data は配列の要素の数を返す
for ($i = 0 ; $i <= $#data ; $i++) {
# 0カラム目で無ければ区切り文字のタブを挿入
# \t はタブを挿入
# .= は左辺の変数に右辺の文字列を追加していく。
if ($i != 0) {
$out_data .= "\t";
}
# 性別の指定カラムの場合は性別を判定。
if ($i == $num) {
# 男性であれば1、女性なら2を代入、
# どちらでもなければそのままの値を挿入
if ($data[$i] eq "男性") {
$out_data .= 1;
} elsif ($data[$i] eq "女性") {
$out_data .= 2;
} else {
$out_data .= $data[$i];
}
} else {
# 性別の指定カラムでなければそのまま代入
$out_data .= $data[$i];
}
# 最後のカラムの場合は改行を入力
if ($i == $#data) {
$out_data .= "\n";
}
}
}
# オープンした入力ファイルをクローズ
close(IN);
# 変更したデータを出力する為にファイルをオープン
# 既存でファイルがあれば上書きされる
open(OUT, ">$out_file") || die "Can't open file [$out_file].";
# 置換データを書き込む
printf(OUT "%s", $out_data);
# オープンした入力ファイルをクローズ
close(OUT);
# 正常終了として0を返してプログラム終了
exit(0);
こんばんは。
ある程度のスキルは必要かと思いますが以下のサイトでcgiを使用出来るサーバをレンタルしてください。
無料でレンタル出来るかと思います。
次に変換するソースを作ってアップします。
ソースは以下を参考にしてみてください。
http://perl.misty.ne.jp/index.html
基本的には「11ファイルの処理」と「08文字の扱い」と「03処理の制御1」の処理が参考になるかと思います。
すでに動作するサーバはあり、簡単にはテストをしていますが、記述方法がいまいち不明です。。
サンプルページがあるとうれしいのですが。
$record に1行毎のデータが入っているとして…
# フォーマットは以下の通り # $record = "年月日\t氏名\t誕生月\t誕生日\t性別"; # タブ区切りでフィールドを分割 ($date,$name,$month,$day,$sex) = split(/\t/,$record); # 1桁(=10未満)なら0を補完 $month = "0" . $month if($month < 10); # 性別の判定 if($sex eq "男性") { $sex = "1"; elsif($sed eq "女性") { $sex = "2"; }
あとはループで処理すればOKかと思います。
どの辺りが不明なのかもう少し教えて頂けますか。
1、ファイルのオープン・クローズは分からないのか?
2、文字列の中から任意の文字の変換が分からないのか?
まったく同じサンプルのページは無いかと思われますので教えてください。
作ってる間に、似たようなコードを提供してくださった方がいたみたいなんですが
せっかくなので掲載させていただきます。
※動作確認はしましたが、念のためバックアップをとってから試してください。
※私はperlを極めてるわけではないので、他の方がもっとシンプルなコードを提供してくださるかもしれません。
open (FH,"+< test.csv"); #読み書きモードでファイルをオープン
@line=<FH>; #ファイルを行ごとの配列に格納
chomp(@line); #改行コード切捨て
$line_amount=$#line+1; #行数計算
#各行を列単位に分割
for($i=0;$i<$line_amount;$i++){
($nengappi[$i],$shimei[$i],$tanjyoutuki[$i],$tanjyoubi[$i],$seibetu[$i])=split(/\t/,$line[$i]);
}
#誕生月の処理
for($i=0;$i<$line_amount;$i++){
$tanjyoutuki[$i]=sprintf("%02d",$tanjyoutuki[$i]);
}
#性別の処理
for($i=0;$i<$line_amount;$i++){
if($seibetu[$i] eq "男性") {
$seibetu[$i]=1;
}
elsif($seibetu[$i] eq "女性"){
$seibetu[$i]=2;
}
}
truncate(FH, 0); #ファイルをゼロクリア
seek(FH,0,0); #ファイルポインタを先頭に移動
#処理したデータを書き込み
for($i=0;$i<$line_amount;$i++){
print FH $nengappi[$i]."\t".$shimei[$i]."\t".$tanjyoutuki[$i]."\t".$tanjyoubi[$i]."\t".$seibetu[$i]."\n";
}
close (FH);
質問者さんはperlを勉強したいのでしょうか?
それとも、今回、たまたまこのようなシステムが必要になっただけで習得は望んでいないのでしょうか?
前者の場合は、ソースコードをまるまる渡すという行為はよくなかったかもしれませんね。
前者かもしれないので、perlの基礎講座のようなサイトをいくつかのせておきます。
http://www.site-cooler.com/kwl/perl/
http://www.kent-web.com/perl/index.html
http://www.poizun.jp/content/cgi/reference/
ありがとうございます。
どちらかというと勉強したいというより、仕事で急に必要になったものですから。。。
こんな感じでしょうか?
#!/usr/bin/perl
print "Content-Type: text/plain\n\n"; # HTTPレスポンスヘッダ
my $file = 'test.csv'; # 読み込むファイル名
open(my $fd, $file); # ファイルを開く
print scalar <$fd>; # 1行目はそのまま出力
foreach (<$fd>) { # 以下1行ずつ読み込み
chop; # 行末の改行削除
my @cols = split("\t", $_); # タブで分割して配列へ
$cols[2] = sprintf('%02d', $cols[2]); # 2桁目は0フィル2桁整数変換
$cols[4] = 1 if $cols[4] eq '男性'; # 4桁目は男性なら1
$cols[4] = 2 if $cols[4] eq '女性'; # 4桁目は女性なら2
print join("\t", @cols), "\n"; # タブで結合して改行をつけて出力
}
close($fd); # ファイルを閉じる
実際には文字コード違いへの配慮や余計な空白の除去や諸々の例外処理を考える必要がありますが、その辺ばっさり省略しています。
蛇足ですが、CSV は Comma Separated Value (カンマで区切られた値) という意味ですので、タブ区切りテキストなら TSV (Tab Separated Value) と呼ぶのが適切かと思います。(Excel の場合拡張子は .txt になりますが)
プログラムは人のを見て理解するのが上達の早道と思います。
割と定番サイトですが、perlの関数や書式、演算子などは、
以下がわかりやすいと思います。
http://pzxa85.hp.infoseek.co.jp/www/wwwperl.htm
ご提示の例ですと以下のようなプログラムでいけると思います。
後はデータの形式などにあわせて、
多少改良するといけると思います(動作確認済みです)。
中にコメントも入れておきましたので参考にしてください。
######################################################################
# 前提
#
# 入力データは以下の形式とする。
# 但し、5カラム目以降も、任意のデータがあった場合でもそのまま格納できる。
#
# 060904 日本太郎 10 4 男性
# 060904 日本花子 9 4 女性
#
# 1データ一行で、区切り文字はタブ1つのみ
# 性別は 4 カラム目にあるとする(0から数えて4カラム目)
# 0カラム目:年月日
# 1カラム目:氏名
# 2カラム目:誕生月
# 3カラム目:誕生日
# 4カラム目:性別
######################################################################
######################################################################
# 以下、条件に合わせて書き換える
# 入力ファイル名を以下に指定。
$in_file = "in.txt";
# 入力ファイル名を以下に指定。
$out_file = "out.txt";
# 性別が4カラム目にある場合は4を指定。
$num = 4;
######################################################################
# 前提が変わらない場合はこれ以降の変更は不要。
#
# 入力ファイルをオープン
open(IN, "$in_file") || die "Can't open file [$in_file].";
# 置換した後のデータを入れる為の変数を初期化
$out_data="";
# ループ処理で全ての行にわたって処理
while (<IN>) {
# 行末に改行文字があれば削除
chomp;
# 1行のデータをタブで区切られた項目ごとに変数に格納
# 以下の例では、
# $data[0] に0カラム目
# $data[1] に1カラム目
# というように格納される
@data = split(/\t/);
# カラム毎に処理を行う
# $#data は配列の要素の数を返す
for ($i = 0 ; $i <= $#data ; $i++) {
# 0カラム目で無ければ区切り文字のタブを挿入
# \t はタブを挿入
# .= は左辺の変数に右辺の文字列を追加していく。
if ($i != 0) {
$out_data .= "\t";
}
# 性別の指定カラムの場合は性別を判定。
if ($i == $num) {
# 男性であれば1、女性なら2を代入、
# どちらでもなければそのままの値を挿入
if ($data[$i] eq "男性") {
$out_data .= 1;
} elsif ($data[$i] eq "女性") {
$out_data .= 2;
} else {
$out_data .= $data[$i];
}
} else {
# 性別の指定カラムでなければそのまま代入
$out_data .= $data[$i];
}
# 最後のカラムの場合は改行を入力
if ($i == $#data) {
$out_data .= "\n";
}
}
}
# オープンした入力ファイルをクローズ
close(IN);
# 変更したデータを出力する為にファイルをオープン
# 既存でファイルがあれば上書きされる
open(OUT, ">$out_file") || die "Can't open file [$out_file].";
# 置換データを書き込む
printf(OUT "%s", $out_data);
# オープンした入力ファイルをクローズ
close(OUT);
# 正常終了として0を返してプログラム終了
exit(0);
サンプルありがとうございます。
以下のように書いたところ、"女性"の条件に入らなくてはならない場合に
"男性"の条件に入ってしまいます。
なぜでしょうか?
if ($data[$i] == "男性") {
$data[$i] = '1';
print "AAA";
}elsif ($data[$i] == "女性") {
$data[$i] = '2';
print "BBB";
}else {
$data[$i] = $data[$i];
print "CCC";
}
#!/usr/bin/perl
# ファイル読み込み
open(IN,"test.csv");
while (<IN>) {
# タブ区切りのデータを分割
($date,$name,$month,$day,$sex) = split(/\t/,$_);
# $monthが10以下なら0を頭に付ける処理
if ($month < 10) {
$month = '0' . $month;
}
# 性別によって数字を代入する処理
if ($sex eq "男性") {
$sex = 1;
} elsif ($sex eq "女性" {
$sex = 2;
} else {
$sex = 3;
}
# $date:年月日
# $name:氏名
# $month:2桁の誕生月
# $day:誕生日
# $sex:1 or 2
# この後何らかの処理を入れてください。
}
close(IN);
ところで、タブ区切りのデータは拡張子をtsvとするのが一般的です。
サンプルありがとうございます。
以下のように書いたところ、"女性"の条件に入らなくてはならない場合に
"男性"の条件に入ってしまいます。
なぜでしょうか?
if ($data[$i] == "男性") {
$data[$i] = '1';
print "AAA";
}elsif ($data[$i] == "女性") {
$data[$i] = '2';
print "BBB";
}else {
$data[$i] = $data[$i];
print "CCC";
}