今ならHTML5で
input
要素にtype="email"
が使えますし、そもそも検証せずとも実際に送ってみればいいのですが、やっぱり事前に検証したいというときもありますよね。ただ、RFC5321やRFC5322で規定されているメールアドレスの形式って結構複雑で、ほとんどのサービスでは簡易的に正規表現でチェックしてたりします
そこで、できるだけRFCに準拠した正規表現に挑戦してみました。
とりあえず結果教えろ
はい。/^([\w!#$%&'*+\-\/=?^`{|}~]+(\.[\w!#$%&'*+\-\/=?^`{|}~]+)*|"([\w!#$%&'*+\-\/=?^`{|}~. ()<>\[\]:;@,]|\\[\\"])+")@(([a-zA-Z\d\-]+\.)+[a-zA-Z]+|\[(\d{1,3}(\.\d{1,3}){3}|IPv6:[\da-fA-F]{0,4}(:[\da-fA-F]{0,4}){1,5}(:\d{1,3}(\.\d{1,3}){3}|(:[\da-fA-F]{0,4}){0,2}))\])$/
なるほど、わかりやすい!
とりあえず使えればいいや!
…という人は何も考えずにコピペして使ってください。
わけわかんねーよ解説しやがれ
…という人は以下を読んでください。読んでも理解できる保証はありませんが。
わけわかんねー人のための解説
…解説していこうと思って途中まで書いたんですが、もうややこしくて仕方ない。生成過程を公開するので、なんとか解析してください。
// 各パートで使用可能な文字セット(デリミタや特殊文字を除く) const REGEXP_CHARSET_DOT = "[\\w!#$%&'*+\\-\\/=?^`{|}~]"; // dot-string const REGEXP_CHARSET_QUOTED = "[\\w!#$%&'*+\\-\\/=?^`{|}~. ()<>\\[\\]:;@,]"; // quoted-string const REGEXP_CHARSET_TLD = "[a-zA-Z]"; // トップレベルドメイン const REGEXP_CHARSET_SLD = "[a-zA-Z\\d\\-]"; // サブレベルドメイン const REGEXP_CHARSET_IPV4 = "\\d"; // IPv4 const REGEXP_CHARSET_IPV6 = "[\\da-fA-F]"; // IPv6 // 各パートの構成要素として受理可能なパターン(デリミタや特殊文字を除く) const REGEXP_COMPONENT_DOT = `${REGEXP_CHARSET_DOT}+`; const REGEXP_COMPONENT_QUOTED = `(${REGEXP_CHARSET_QUOTED}|\\\\[\\\\"])+`; const REGEXP_COMPONENT_TLD = `${REGEXP_CHARSET_TLD}+`; const REGEXP_COMPONENT_SLD = `${REGEXP_CHARSET_SLD}+`; const REGEXP_COMPONENT_IPV4 = `${REGEXP_CHARSET_IPV4}{1,3}`; const REGEXP_COMPONENT_IPV6 = `${REGEXP_CHARSET_IPV6}{0,4}`; // ローカル部 const REGEXP_LOCAL_DOT = `${REGEXP_COMPONENT_DOT}(\\.${REGEXP_COMPONENT_DOT})*`; const REGEXP_LOCAL_QUOTED = `"${REGEXP_COMPONENT_QUOTED}"`; const REGEXP_LOCAL = `(${REGEXP_LOCAL_DOT}|${REGEXP_LOCAL_QUOTED})`; // ドメイン部 const REGEXP_DOMAIN_GENERAL = `(${REGEXP_COMPONENT_SLD}\\.)+${REGEXP_COMPONENT_TLD}`; const REGEXP_DOMAIN_IPV4 = `${REGEXP_COMPONENT_IPV4}(\\.${REGEXP_COMPONENT_IPV4}){3}`; const REGEXP_DOMAIN_IPV6_COMMON = `${REGEXP_COMPONENT_IPV6}(:${REGEXP_COMPONENT_IPV6}){1,5}`; const REGEXP_DOMAIN_IPV6_REST = `(:${REGEXP_DOMAIN_IPV4}|(:${REGEXP_COMPONENT_IPV6}){0,2})`; const REGEXP_DOMAIN_IPV6 = `IPv6:${REGEXP_DOMAIN_IPV6_COMMON}${REGEXP_DOMAIN_IPV6_REST}`; const REGEXP_DOMAIN_IP = `\\[(${REGEXP_DOMAIN_IPV4}|${REGEXP_DOMAIN_IPV6})\\]`; const REGEXP_DOMAIN = `(${REGEXP_DOMAIN_GENERAL}|${REGEXP_DOMAIN_IP})`; // メアド = ローカル部 + "@" + ドメイン部 const REGEXP_EMAIL = `^${REGEXP_LOCAL}@${REGEXP_DOMAIN}$`; const PATTERN = new RegExp(REGEXP_EMAIL);
注意点
- RFCに完全に準拠しているわけではありません。ほとんどのパターンでは正常に判定できますが、準拠していないものを通してしまう場合も一部あります。
- IPv6部分が正常に判定できない場合があります。
- IPv4部分も、255より大きな数値が指定されても受理してしまいます。
- RFCではローカル部、ドメイン部、全体の長さに制限がありますが、チェックしていません。
- ドメイン部の一部に、病理的な正規表現を使っています。
- 正規表現のエンジンやマッチングする文字列によっては、まれにマッチング速度がとても遅くなることがあります。
- …とはいってもめちゃくちゃヤバいものではなく、意識しないとみなさんも思わずやってしまいがちなレベルです。
0 件のコメント:
コメントを投稿