2008/02/07 修正 (
- Blogger投稿時に、バックスラッシュ2つが1つに変換されていた(全角で掲載することにより回避。全角の¥は半角に読み替えてください!)
- domainの先頭は数字でもOKにした(ドメイン制限の緩和に合わせた)
- domainのlabelの最後に?を追加(漏れていた)
)
何回か挫折したけどもう一度チャレンジしてみた。
RFC 2822を読み解くのは辛いので、基準として
「正しい方法」でメールアドレスを確認するには - J0hn D0e の日誌に書いてある『「正しいメールアドレスの条件」10か条』をなるべく満たすことを目指した。
できたのはこれ。
preg_match('/^([-!#-¥¥'*+¥¥/-9=?^-~]+(¥¥.[-!#-¥¥'*+¥¥/-9=?^-~]+)*|"([]-~!#-[]|¥¥¥¥[ -~])*")@[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?(¥¥.[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?)*¥¥.([a-z]{2,4}|museum)$/i', $value)
10か条のうち、1~4と6~8を満たしている(と思う)。
以下は未対応
- 10は正規表現では無理
- 5と9も正規表現では無理だよね?
- 3(quoted-string)については、RFC 2822を見た感じではlocal-part全体がquoted-stringの場合のみ使えるように見えるけど、symfonyではlocal-partの一部としてもquoted-stringを許しているのは何故?
- 4(quoted-pair)については、RFC 2822を見た感じではquoted-string内でのみ使えるように見えるけど、「正しい方法」でメールアドレスを確認するにはを読んだ感じだとlocal-part内ならどこでも使えるみたいに書いてあるからそうなのかな???
現実問題としては、DoCoMo(Softbankも?)は
RFC2822違反のメールアドレスでも登録できてしまうので、下記のような"DoCoMo版メールアドレス"は上記の正規表現ではエラーになってしまう。
ついでに、上記の正規表現を生成したPHPのソースコードはこちら。
(コメントの番号は10か条の番号に対応)
<?php
if (!$m = $_REQUEST['m']) $m = 'test@example.com';
//local part
$atext = "[-!#-'*+/-9=?^-~]";
$atom = $atext . '+';
$dot_atom = $atom . '(¥¥.' . $atom . ')*'; //2
$qtext = '[]-~!#-[]';
$text = '[ -~]';
$quoted_pair = '¥¥¥¥' . $text; //4
$quoted_string = '"(' . $qtext . '|' . $quoted_pair . ')*"'; //3
$local_part = '(' . $dot_atom . '|' . $quoted_string . ')';
//domain
$label = '[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?'; //7, 8
$domain = $label . '(¥¥.' . $label . ')*¥¥.([a-z]{2,4}|museum)'; //6
//全体
$addr_spec = $local_part . '@' . $domain; //1
$regexp = '/^' . str_replace('/', '¥¥/', $addr_spec) . '$/i';
?>
正規表現<br />
<?php echo $regexp; ?>
<hr />
preg_match('<strong><?php echo str_replace(array("'", '¥¥'), array("¥¥'", '¥¥¥¥'), $regexp); ?></strong>', $value)
<hr />
<form action="regex.php">
<input name="m" value="<?php echo htmlSpecialChars($m, ENT_QUOTES); ?>" />
は、正し<?php echo (preg_match($regexp, $m) ? 'い' : 'くない') ?>メールアドレスです。
</form>
一般的には、これくらいやれば十分でしょう。
preg_match('/^[-+¥¥w]+(¥¥.[-+¥¥w]+)*@[-a-z0-9]+(¥¥.[-a-z0-9]+)*¥¥.[a-z]{2,6}$/i', $value)
DoCoMoも救済するならもう少しシンプルになる。実際に使うならこれで。
local-partに入れる記号は"-_."くらいが一般的で、Gmailerは"+"も使うからそれぐらい対応すれば99%くらいはカバーすると思う。これでダメなメールアドレスは弾いちゃった方が何かと安心な気がする...。
preg_match('/^[-+.¥¥w]+@[-a-z0-9]+(¥¥.[-a-z0-9]+)*¥¥.[a-z]{2,6}$/i', $value)
参考:
「正しい方法」でメールアドレスを確認するには - J0hn D0e の日誌 http://www.puni.net/~mimori/rfc/rfc2822.txt (Internet Message Format)
ASCII文字コード : IT用語辞典 正規表現 perlre - Perlの正規表現 re: PHPでメールアドレスかどうか調べる方法 (ハズレ日記)