フォームに入力された内容をCSVに書き込みます。次の2つの条件によってCSVに書き込む内容を分岐するにはどこを修正すればよいでしょうか?お智恵をお借りできれば幸いです。
1.メルマガ($newsletter)の値が"希望する"または"登録済み"の場合で
2.docomo,ezweb,softbank,vodafoneを含む携帯アドレスならmail_keitai.csvにそれ以外はmail.csvに書き込む
※これはhttp://q.hatena.ne.jp/1203118562#a802935の派生質問です。アドレスがすでにCSVに存在する場合は2つの条件が当てはまっても書き込みません。
$csv = "1";
$file = "./mail.csv";
$file2 = "./mail_keitai.csv";
$lock = "./lock/mail.dat";
$mail = $FORM{'mail'};
$name = $FORM{'name'};
$newsletter = $FORM{'newsletter'};
$mail2 = $FORM{'mail2'};
#書きこむ
open(FILE, "<$file") or &err2('エラーです。');
@lines= <FILE>;
close(FILE);
for($x=0;$x <= $#lines;$x++){
my @HashTmp = split("\,",$lines[$x]);
$Hname{$HashTmp[2]} = $HashTmp[1];
}
unless(exists($Hname{$mail})){
unshift(@lines,"$name,$mail\n");
open(OUT, "+<$file") or &err2();
print OUT @lines;
close(OUT);
}
まず条件を整理します。
1)$newsletterが「希望する」又は「登録する」の場合は書き込み処理を行う。
2)$mailにdocomo,ezweb,softbank,vodafoneのいずれかが含まれれば$file2に書き込み、当てはまらなければ$fileに書き込む。
1の条件式は、($newsletter eq '希望する' || $newsletter eq '登録する') となります。
2で真を返す正規表現は、($mail =~ /(docomo|ezweb|softbank|vodafone)/) となります。
他の方は$fileを上書きする方法を採られていますが、私は専用の変数(この場合$wfile)を使用する方が好きです。(単に好みの問題です)
$csv = "1"; $file = "./mail.csv"; $file2 = "./mail_keitai.csv"; $lock = "./lock/mail.dat"; $mail = $FORM{'mail'}; $name = $FORM{'name'}; $newsletter = $FORM{'newsletter'}; $mail2 = $FORM{'mail2'}; #書きこむ #newsletterの値が'希望する'か'登録する'ならば実行する。 #それ以外なら何もしない if($newsletter eq '希望する' || $newsletter eq '登録する'){ #メールアドレス内文字列の判定を行う my $wfile; # $wfileを局所化します。他で使っていなければやらなくてもOK if($mail =~ /(docomo|ezweb|softbank|vodafone)/){ $wfile = $file2; }else{ $wfile = $file; } open(FILE, "<$wfile") or &err2('エラーです。'); @lines= <FILE>; close(FILE); for($x=0;$x <= $#lines;$x++){ my @HashTmp = split("\,",$lines[$x]); $Hname{$HashTmp[2]} = $HashTmp[1]; } unless(exists($Hname{$mail})){ unshift(@lines,"$name,$mail\n"); open(OUT, "+<$wfile") or &err2(); print OUT @lines; close(OUT); } }
ただ、質問文を読んでみると携帯電話用のアドレスとそれ以外のアドレスを別々のファイルで管理したいかの様に思えます。
($mail =~ /(docomo|ezweb|softbank|vodafone)/) ですと、例えば「docomonsense@hatena.ne.jp」(DoCommonSenseのミススペル)も「携帯電話アドレス」と判定されます。
Docomoのメールアドレスは、~@docomo.ne.jp
ezwebのメールアドレスは、~@ezweb.ne.jp
SoftBankのメールアドレスは、~@softbank.ne.jp
Vodafoneのメールアドレスは、~@*.vodafone.ne.jp
ですので、
($mail =~ /(\@docomo\.ne\.jp|\@ezweb\.ne\.jp|\@softbank\.ne\.jp|\.vodafone\.ne\.jp)/)
が適切かと。
更に、これらのドメインは末尾にくるはずなので、
($mail =~ /(\@docomo\.ne\.jp|\@ezweb\.ne\.jp|\@softbank\.ne\.jp|\.vodafone\.ne\.jp)$/)
この場合の//内の「$」は、文字列の末尾を表します。
ついでに、ドメインネームについては大文字小文字を区別しませんので、
($mail =~ /(\@docomo\.ne\.jp|\@ezweb\.ne\.jp|\@softbank\.ne\.jp|\.vodafone\.ne\.jp)$/i)
//の外の「i」は、大文字小文字を区別しないパターンマッチを行う修飾子です。
これをメールアドレス内文字列の判定に適用すると、
#メールアドレス内文字列の判定を行う my $wfile; # $wfileを局所化します。他で使っていなければやらなくてもOK if($mail =~ /(\@docomo\.ne\.jp|\@ezweb\.ne\.jp|\@softbank\.ne\.jp|\.vodafone\.ne\.jp)$/i){ $wfile = $file2; }else{ $wfile = $file; }
こんな感じになるかと思います。
また、[例えば]ezwebが~@*.ezweb.ne.jp というメールアドレスも使い始めたら、「\@ezweb\.ne\.jp」の後にでも「|\.ezweb\.ne\.jp」を書き加えます。「\.ezweb\.ne\.jp」は、()外の$と合わさり「末尾が.ezweb.ne.jpで終わる」文字列にマッチします。
ウィルコムも仲間に加える場合は、
($mail =~ /(\@docomo\.ne\.jp|\@ezweb\.ne\.jp|\@softbank\.ne\.jp|\.vodafone\.ne\.jp|\.pdx\.ne\.jp|\@pdx\.ne\.jp)$/i)
です。
最近 perl を書いていないのでチョッと不安がありますが、こんな感じでしょうか。
1)
# 書きこむ
の行の前で、$newsletter の値が"希望する"または"登録済み"でない場合は、このルーチンから抜ければOKでは?
if ($newsletter eq '希望する' || $newsletter eq '登録済み') exit; # または return;
2)
こちらも
# 書きこむ
の行の前でキーワードを含めば、携帯用に書き換えるとよいと思います。
$file = './mail.csv';
if ($mail =~ /(docomo|ezweb|softbank|vodafone)/) $file = $file2; # 前以て$file2を定義せずにここで直接書いても可
条件部分を、
(!($newsletter eq '希望する' || $newsletter eq '登録する')) にするか、
($newsletter ne '希望する' && $newsletter ne '登録する') にするかで迷ってて...
ブール代数の基本なのでお分かりになるとは思いましたが、質問文に近い形の方が理解しやすいかなぁと。
その結果が間違っていては「何だかなぁ〜」ですが。
どんなエラーが表示されるのでしょうか? >ictaさん
(サーバにもよりますが)どの行でとか、どんなエラーとか出てませんか?
もしも「エラーです。」だけ出ているのでしたら、ファイルのオープンに失敗したときにスクリプト中で出力しているヤツでは?(カレントのディレクトリにはperlに作成のパーミッションがないとか...)
仰せの通りです >kiryuu さん
知り合いに、○○○.vodafone.ne.jp@ezweb.ne.jp なんてアドレスをつけているヤツが居たのを思い出しました。
なので、@以降である事は明示すべきでしょうね。
vodafone も、@[dhtcrknsq]¥.vodafone¥.ne¥.jp で指定可能ですね。
KDDI, Wilcom がどのようなアドレスなのかは知りませんが、@¥w*?¥.?ezweb¥.ne¥.jp のように出来るかも知れません。(ごめんなさい。うまくマッチするかは未確認です)
で、全部に@があるのなら()の前に出してしまった方が見やすいですね。
(たしか、@はメタ文字ではなかったと思うので、エスケープは不要では?)
2)の方は、いつもなら
$file = './mail';
if ($mail =~ ........) $file .= '_keitai';
$file .= '.csv';
とするだろうなぁと思います。せっかく $file2 が用意されているので回答したようにしました。
(.csv を_keitai.csv と置き換えるように書いたのもあったっけ)
自分でファイル名を決めるのなら、文字の連結が2回で済むようにする為、'mail.csv' , 'kmail.csv' か、'csv_mail', 'csv_mail_k' (あまりWinからダブルクリックで開く事を重視しないので、拡張子にcsvが無くても気にしない為)にすると思います。
まぁ、やり方は人それぞれで、色々あるって事ですね。
実際に動かしてみました。@はエスケープ不要ですね。ご指摘ありがとうございます。
vodafoneのサブドメインについては、資料がちょっと見つからなかったのですが、今しがたヤフオクの「モバイル版「Yahoo!かんたん決済」のURLをケータイに送信する」のフォームを見たところ、[dhtcrknsq]であっているようです。(Vodafoneを引き継いだSoftBankの記述をある程度信頼するとして)
/@(docomo\.ne\.jp|ezweb\.ne\.jp|softbank\.ne\.jp|[dhtcrknsq]\.vodafone\.ne\.jp|\w*?\.?pdx\.ne\.jp)$/i
でテストしてみましたが、どうやら正常に動いているようです。(perl 5.8.6)
エラーと表示される件:
tezcelloさんご指摘の通り、「エラーです。」表示でしたら、ファイル操作周辺でのエラーかと思います。
open(FILE, "<$file") で失敗したときに出す設定ですので、$file(mail.csv若しくはmail_keitai.csv)が
・読み込むべきファイルが存在しない
・ファイルのパーミッションが適切でない
のいずれかが原因だと推測します。
ファイルがない場合は、空ファイルを作ってFTPでアップするか(シェル上でtouchしてもいいかと)、スクリプト内で作成するのがよろしいかと。
スクリプト内で処理するとなるとこんな感じ?
>||
if(-e $wfile){
open(FILE, "<$wfile") or &err2('エラーです。');
@lines= <FILE>;
close(FILE);
}else{
open(FILE,">$wfile") or &err2("$fileの生成に失敗");
close(FILE);
chmod 0606,$wfile;
@lines = ();
}
||<
($wfileは私の回答の場合)
カレントディレクトリのパーミッションを707等にするのをお忘れなく。
707が不安なのであれば、やはり予めファイルを作っておく必要があります。
パーミッションが合っていない場合は、$fileのファイルのパーミッションを設定しましょう。(606。suExec下であれば600)
#ifのブロック内が長くなるのはあまり好きじゃないので、私の場合はサブルーチンに分けたりしちゃいます。
これを日本語にすると、
$birthmonth が '-' でない、または、$birthday が '-' でない の場合となります。
つまり、$birthmonth と $birthday のどちらか一方でも '-' ではない場合は書き込み処理をしてしまいます。
お望みの処理は、どちらか一方でも '-' が選択された場合は書き込まない というのだと思うのですが、それならば
($birthmonth ne '-' && $birthday ne '-')
という事でしょうね。
>これを日本語にすると、
>$birthmonth が '-' でない、または、$birthday が '-' でない の場合となります。
ですね。
$birthmonth か $birthday どちらか(又は両方)が“-”でなければという条件なら
($birthmonth ne '-' || $birthday ne '-')
ですが、
両方“-“でない場合の式は、
($birthmonth ne '-' && $birthday ne '-')
であるというのは同見解です。
ついでに、$newsletterの条件と合わせるなら
(($newsletter eq '希望する' || $newsletter eq '登録する') && ($birthmonth ne '-' && $birthday ne '-'))
でしょうか。
期待通りの仕様で大変うれしいです。
これまで何年も手作業で行っていた作業からようやく解放されます。
完璧に動作するのを見たらこれまで何と時間を無駄にしてきたことかと考えさせられました。
CGIはまだよくわかっていないのでこれを契機に勉強してみたいと思います。
本当にありがとうございました。