クイックスタート
チュートリアル
ツールと言語
リファレンス
書評
正規表現の例
数値範囲
浮動小数点数
メールアドレス
IPアドレス
有効な日付
数値日付をテキストに変換
クレジットカード番号
完全な行の一致
重複行の削除
プログラミング
2つの近接した単語
落とし穴
カタストロフィックバックトラッキング
過剰な繰り返し
サービス拒否
すべてをオプションにする
キャプチャグループの繰り返し
Unicodeと8ビットの混合
このサイトについてもっと詳しく
はじめに
正規表現クイックスタート
正規表現チュートリアル
置換文字列チュートリアル
アプリケーションと言語
正規表現の例
正規表現リファレンス
置換文字列リファレンス
書評
印刷可能なPDF
このサイトについて
RSSフィードとブログ
RegexMagic—Generate regular expressions matching email addresses

メールアドレスの検索または検証方法

最も多くのフィードバック、そして「バグ」報告を受け取る正規表現は、このサイトのホームページにあります。\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\bこの正規表現は、すべてのメールアドレスにマッチすると主張しています。しかし、多くのフィードバックでは、この正規表現にマッチしないメールアドレスが示され、その主張は反論されています。「バグ」報告には、通常、正規表現を「完璧」にするための提案も含まれています。

以下で説明するように、私の主張は、有効なメールアドレスとそのそうでないものの定義を受け入れる場合にのみ成り立ちます。異なる定義を使用する場合は、正規表現を調整する必要があります。有効なメールアドレスにマッチさせることは、(1)正規表現を作成する前に、正確に何をマッチさせたいか、そして何をマッチさせたくないかを理解する必要があり、(2)正確さと実用性の間にトレードオフがあることの完璧な例です。

上記の正規表現の長所は、現在使用されているメールアドレスの99%にマッチすることです。マッチするすべてのメールアドレスは、99%のメールソフトウェアで処理できます。迅速な解決策を探している場合は、次の段落を読むだけで済みます。すべてのトレードオフを知り、多くの選択肢の中から選ぶ必要がある場合は、読み進めてください。

上記の正規表現を使用する場合は、2つの点に注意する必要があります。まず、長い正規表現は、段落をきれいにフォーマットすることを困難にします。そのため、a-zを3つの文字クラスのいずれにも含めませんでした。この正規表現は、正規表現エンジンの「大文字と小文字を区別しない」オプションがオンになっている状態で使用することを目的としています。(その点に関する「バグ」報告の多さに驚かれるかもしれません。)第二に、上記の正規表現は単語境界で区切られているため、ファイルやより大きなテキストブロックからメールアドレスを抽出するのに適しています。ユーザーが有効なメールアドレスを入力したかどうかを確認する場合は、単語境界を文字列の先頭と末尾のアンカーに置き換えます。以下のように^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$.

前の段落は、以下のすべての例にも当てはまります。単語境界を文字列の先頭/末尾のアンカーに変更する必要がある場合や、その逆の場合があります。また、大文字と小文字を区別しないマッチングオプションを有効にする必要があります。

メールアドレスの検証におけるトレードオフ

ICANNが資金力のある企業が独自のトップレベルドメインを作成することを可能にする前に、最長のトップレベルドメインは、めったに使用されない.museum.travelで、6文字の長さでした。最も一般的なトップレベルドメインは、国固有のドメインでは2文字、.com や .info のような汎用ドメインでは3文字または4文字の長さでした。.com.infoさまざまな正規表現のチュートリアルやリファレンスで見つかるメールアドレスを検証するための多くの正規表現は、トップレベルドメインがかなり短いものだとまだ仮定しています。この正規表現チュートリアルの旧版では、\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\bを導入部でメールアドレスの正規表現として挙げていました。この正規表現とこのページの上部にある正規表現との間には、わずかな違いが1つだけあります。正規表現の末尾の4は、トップレベルドメインを4文字に制限しています。注文フォームに入力されたメールアドレスを検証するためにこの正規表現をアンカーで使用する場合、fabio@disapproved.solutionsは、他の場所で買い物をする必要があります。はい、.solutionsTLDは存在し、私がこれを書いている時点では、disaproved.solutionsは年間16.88ドルで購入できます。

より厳密にする必要がある場合は、[A-Z]{2,}をトップレベルドメインに使用し、^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,63}$が実用的な限界です。ドメイン名の各部分は、63文字を超えることはできません。1桁のトップレベルドメインはなく、数字を含むものもありません。ICANNがそのようなドメインを承認するようには見えません。

メールアドレスは、サブドメイン上のサーバーにある場合もあります。たとえば、john@server.department.company.comなどです。上記のすべての正規表現は、@記号の後の文字クラスにドットを含めたため、このメールアドレスにマッチします。しかし、上記の正規表現はjohn@aol...comにもマッチします。これは、連続するドットがあるため無効です。このようなマッチを排除するには、[A-Z0-9.-]+\.(?:[A-Z0-9-]+\.)+に置き換えます。上記の正規表現のいずれかで、ドットを文字クラスから削除し、代わりに文字クラスとそれに続くリテラルドットを繰り返しました。例:^[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,}$はマッチしますが、john@server.department.company.comはマッチしません。john@aol...com.

システムが任意に大きな入力で詰まるのを防ぐには、無限の量子化子を有限のものに置き換えることができます。^[A-Z0-9._%+-]{1,64}@(?:[A-Z0-9-]{1,63}\.){1,125}[A-Z]{2,63}$は、ローカルパート(@の前)が64文字に制限され、ドメイン名の各部分が63文字に制限されていることを考慮に入れています。サブドメインの数には直接的な制限はありません。しかし、SMTPで処理できるメールアドレスの最大長は254文字です。そのため、1文字のローカルパート、2文字のトップレベルドメイン、1文字のサブドメインの場合、125がサブドメインの最大数になります。

前の正規表現は、実際にはメールアドレスを254文字に制限していません。各部分が最大長のとき、正規表現は最大8129文字の長さの文字列にマッチできます。サブドメインの許容数を125からより現実的な8に減らすことで、それを減らすことができます。4つ以上のサブドメインを持つメールアドレスを見たことはありません。254文字の制限を適用する必要がある場合、最適な解決策は、正規表現を使用する前に入力文字列の長さを確認することです。これはいくつかの手続き型コードを必要としますが、文字列の長さを確認するのにかかる時間はほぼ瞬間的です。正規表現のみを使用できる場合は、^[A-Z0-9@._%+-]{6,254}$を使用して、文字列に無効な文字が含まれていないか、短すぎるか長すぎるかを最初に確認できます。1つの正規表現ですべてを実行する必要がある場合は、先行参照をサポートする正規表現フレーバーが必要です。正規表現^(?=[A-Z0-9@._%+-]{6,254}$)[A-Z0-9._%+-]{1,64}@(?:[A-Z0-9-]{1,63}\.){1,8}[A-Z]{2,63}$先読みを使用して、まず文字列に無効な文字が含まれていないか、短すぎたり長すぎたりしないかをチェックします。先読みが成功すると、残りの正規表現は文字列を2回目に通過して、@記号とドットの配置が適切かどうかをチェックします。

これらの正規表現はすべて、次の文字を許可します。._%+-ローカル部分のどこにでも配置できます。ローカル部分が文字で始まるようにするには、^[A-Z0-9][A-Z0-9._%+-]{0,63}を代わりに使用します。^[A-Z0-9._%+-]{1,64}ローカル部分について^[A-Z0-9][A-Z0-9._%+-]{0,63}@(?:[A-Z0-9-]{1,63}\.){1,125}[A-Z]{2,63}$先読みを使用してアドレス全体の文字数をチェックする場合、先読みで最初の文字をチェックできます。ローカル部分の長さをチェックする際に、最初の文字のチェックを繰り返す必要はありません。この正規表現はページの幅に収まりきらないほど長いため、フリースペースモードをオンにします。

^(?=[A-Z0-9][A-Z0-9@._%+-]{5,253}$)
[A-Z0-9._%+-]{1,64}@(?:[A-Z0-9-]{1,63}\.){1,8}[A-Z]{2,63}$

ドメイン名にはハイフンを含めることができます。ただし、ハイフンで始めることも、ハイフンで終わらせることもできません。[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?は、文字または数字で始まり、文字または数字で終わる、1~63文字の長さのドメイン名に一致します。非キャプチャリンググループにより、1文字のドメインを許可しながら同時に2文字以上のドメインがハイフンで終わらないようにするために、ドメインの中央部分と最後の文字または数字全体をオプションとして設定しています。全体的な正規表現は非常に複雑になり始めています。

^[A-Z0-9][A-Z0-9._%+-]{0,63}@
(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.){1,8}[A-Z]{2,63}$

ドメイン名には連続したハイフンを含めることはできません。[A-Z0-9]+(?:-[A-Z0-9]+)*は、文字または数字で始まり、文字または数字で終わり、連続しないハイフンを任意の数含むドメイン名に一致します。これが最も効率的な方法です。この正規表現は、有効なドメイン名に一致させるためにバックトラッキングを行いません。ドメイン名の先頭にあるすべての文字と数字に一致します。ハイフンがない場合、その後に続くオプションのグループはすぐに失敗します。ハイフンがある場合、グループはハイフンごとに一致し、その後に続くすべての文字と数字を次のハイフンまたはドメイン名の終わりまで一致させます。ハイフンを文字または数字と組み合わせる必要がある場合、最大長を適用することはできませんが、文字と数字は単独で存在できます。しかし、電子メールアドレス全体の文字数を適用するために使用した先読み手法を使用して、連続したハイフンを許可しないようにしながら、ドメイン名の長さを適用できます。(?=[A-Z0-9-]{1,63}\.)[A-Z0-9]+(?:-[A-Z0-9]+)*先読みでは、電子メールアドレスで完全に修飾されている場合、ドメイン名の後に表示される必要があるドットもチェックすることに注意してください。これは重要です。ドットをチェックしないと、先読みはより長いドメイン名を受け入れてしまいます。先読みは一致するテキストを消費しないため、ドットは、この正規表現の全体的な一致には含まれません。この正規表現を電子メールアドレスの全体的な正規表現に入れると、前の正規表現と同じようにドットが一致するようになります。

^[A-Z0-9][A-Z0-9._%+-]{0,63}@
(?:(?=[A-Z0-9-]{1,63}\.)[A-Z0-9]+(?:-[A-Z0-9]+)*\.){1,8}[A-Z]{2,63}$

全体の長さをチェックする先読みを含めると、正規表現はローカル部分を2回、ドメイン名を3回通過してすべてを検証します。

^(?=[A-Z0-9][A-Z0-9@._%+-]{5,253}$)[A-Z0-9._%+-]{1,64}@
(?:(?=[A-Z0-9-]{1,63}\.)[A-Z0-9]+(?:-[A-Z0-9]+)*\.){1,8}[A-Z]{2,63}$

最新のPCまたはサーバーでは、この正規表現は、254文字の電子メールアドレスを1つ検証する場合に問題なく動作します。より長い入力を拒否する方がさらに高速になります。先読みが最初の通過中に失敗すると、正規表現は失敗するためです。ただし、これほど複雑な正規表現を使用して、大量のドキュメントや書簡のアーカイブから電子メールアドレスを検索することはお勧めしません。このページの上部にある単純な正規表現を使用して、電子メールアドレスのように見えるものをすばやく収集する方が良いでしょう。結果を重複排除し、無効なアドレスをさらにフィルタリングする場合は、より厳格な正規表現を使用します。

そして、バックトラッキングについてですが、このページの正規表現はどれも、有効な電子メールアドレスに一致させるためにバックトラッキングを行いません。ただし、特に後者の正規表現は、有効な電子メールアドレスではないものに対してかなりのバックトラッキングを行う可能性があります。正規表現のフレーバーが所有修飾子をサポートしている場合、すべての修飾子を所有修飾子にすることで、すべてのバックトラッキングを排除できます。一致を見つけるためにバックトラッキングは必要ないため、これを行うと、これらの正規表現で一致するものが変更されることはありません。入力が無効な電子メールアドレスの場合にのみ、失敗が速くなります。サブドメインを正しく処理する最も単純な正規表現は次のようになります。^[A-Z0-9._%+-]++@(?:[A-Z0-9-]++\.)++[A-Z]{2,}+$各修飾子の後に追加の+があります。最も複雑な正規表現でも同じことができます。

^(?=[A-Z0-9][A-Z0-9@._%+-]{5,253}+$)[A-Z0-9._%+-]{1,64}+@
(?:(?=[A-Z0-9-]{1,63}+\.)[A-Z0-9]++(?:-[A-Z0-9]++)*+\.){1,8}+[A-Z]{2,63}+$

これらの正規表現すべてにおける重要なトレードオフは、英字、数字、および最も一般的に使用される特殊記号しか許可しない点です。主な理由は、私のすべてのメールソフトウェアがそれ以外を処理できるとは限らないと信頼していないためです。たとえJohn.O'Hara@theoharas.comが構文的に有効なメールアドレスであっても、一部のソフトウェアがアポストロフィを区切り引用符と誤って解釈するリスクがあります。たとえば、このメールアドレスをSQLクエリに無闇に挿入すると、文字列が単一引用符で区切られている場合、最悪の場合、SQLインジェクション攻撃によってサイトが開かれる可能性があり、最善の場合でも失敗します。

そしてもちろん、ドメイン名に英語以外の文字を含めることができるようになってからすでに何年も経っています。しかし、ほとんどのソフトウェアはまだ、西洋のプログラマーが慣れ親しんでいる37文字に固執しています。国際化ドメインをサポートすると、ASCII以外の文字のエンコード方法という、多くの問題が発生します。そのため、このページの正規表現のいずれかを使用する場合、@ทีเอชนิค.ไทยアドレスを持つユーザーは使用できません。しかし、おそらくhttp://ทีเอชนิค.ไทยhttp://thnic.co.thにリダイレクトされることは示唆的です。彼らは.ไทย.ไทยドメインの販売を事業として行っているにもかかわらずです。

結論として、メールアドレスか、漠然と定義されたその他の何かを照合しようとしているかにかかわらず、どの正規表現を使用するかを決定するには、すべてのトレードオフを考慮することから始める必要があります。無効なものを照合することはどれほど悪いことですか?有効なものを照合しないことはどれほど悪いことですか?正規表現はどの程度複雑にすることができますか?広すぎるか狭すぎることが判明した場合に、正規表現を変更する費用はどれくらいかかりますか?これらの質問に対する異なる回答には、ソリューションとして異なる正規表現が必要です。私のメール正規表現は私の希望どおりに動作しますが、あなたの希望どおりに動作するとは限りません。

正規表現はメールを送信しません

正規表現を使用して無効なメールアドレスを除外しようとする際に、やりすぎないようにしてください。理由は、メールアドレスを送信してみるまで、アドレスが有効かどうかは実際にはわからないためです。そして、それでも十分でない場合があります。メールがメールボックスに届いても、まだ誰かがそのメールボックスを読んでいるとは限りません。メールアドレスが本当に有効であることを確認する必要がある場合は、受信者が2段階目の認証手順を実行するためのコードまたはリンクを含むメールを送信する必要があります。そして、そうする場合は、有効なメールアドレスを拒否する可能性のある正規表現を使用する意味はほとんどありません。

同じ原則が多くの状況に適用されます。有効な日付を照合しようとする場合、正規表現で実行しようとするよりも、算術演算を使用して閏年を確認する方が簡単です。正規表現を使用して潜在的な一致を見つけるか、入力で適切な構文が使用されているかどうかを確認し、正規表現によって返された潜在的な一致に対して実際の検証を実行します。正規表現は強力なツールですが、万能薬とはほど遠いものです。

公式規格:RFC 5322

メールアドレスを照合するための「公式」の堅牢な正規表現がないのはなぜかと疑問に思っているかもしれません。公式の定義はありますが、堅牢とは言い難いです。

公式規格はRFC 5322として知られています。これは、有効なメールアドレスが従う必要がある構文を記述しています。これらを次の正規表現で実装できます(ただし、実装すべきではありません—読み進めてください)。RFC 5322は、今日のインターネットでは機能しない実装固有の選択肢にドメイン名部分を公開しています。RFC 1035からの「推奨」構文を実装しています。これはRFC 5322の推奨事項の1つです。

\A(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*
 
|  "(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]
      
|  \\[\x01-\x09\x0b\x0c\x0e-\x7f])*")
@ (?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?
  
|  \[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}
       
(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:
          
(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]
          
|  \\[\x01-\x09\x0b\x0c\x0e-\x7f])+)
     
\])\z

この正規表現には、@の前と@の後の2つの部分があります。@の前には2つの選択肢があります。最初の選択肢では、1つ以上のドットを含む、一連の文字、数字、特定の記号で構成されることを許可します。ただし、ドットは連続して出現したり、メールアドレスの先頭または末尾に現れたりすることはできません。もう一方の選択肢では、@の前にある部分を二重引用符で囲む必要があり、引用符の間のASCII文字の任意の文字列を許可します。空白文字、二重引用符、バックスラッシュは、バックスラッシュでエスケープする必要があります。

@の後の部分にも2つの選択肢があります。完全修飾ドメイン名(例:regular-expressions.info)であるか、角かっこで囲まれたリテラルインターネットアドレスである可能性があります。リテラルインターネットアドレスは、IPアドレスまたはドメイン固有のルーティングアドレスのいずれかです。

この正規表現を使用すべきでない理由は、範囲が広すぎるためです。アプリケーションがこの正規表現で許可されるすべてのメールアドレスを処理できない場合があります。ドメイン固有のルーティングアドレスには、印刷できないASCII制御文字が含まれている可能性があり、アプリケーションでアドレスを表示する必要がある場合に問題を引き起こす可能性があります。すべてのアプリケーションが、二重引用符または角かっこを使用するローカル部分の構文をサポートしているわけではありません。実際、RFC 5322自体では、角かっこを使用した表記法は廃止予定としてマークされています。

IPアドレス、ドメイン固有のアドレス、二重引用符と角かっこを使用した構文を省略すると、RFC 5322の実用的な実装が得られます。それでも、今日実際に使用されているすべてのメールアドレスの99.99%を照合します。

\A[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@
(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\z

これらの正規表現のいずれも、メールアドレス全体、ローカルパート、ドメイン名の長さ制限を強制していません。RFC 5322では長さ制限は指定されていません。それらは、メールの送信に実際に使用されるSMTPプロトコルなどの他のプロトコルの制限に由来します。RFC 1035では、ドメインは63文字以内であると規定していますが、構文仕様には含めていません。真の正規言語では、長さ制限と連続したハイフンの禁止を同時に強制できないためです。しかし、最新の正規表現フレーバーは真に正規のものではないため、前にやったように先行参照を使用して長さ制限チェックを追加できます。

\A(?=[a-z0-9@.!#$%&'*+/=?^_`{|}~-]{6,254}\z)
 
(?=[a-z0-9.!#$%&'*+/=?^_`{|}~-]{1,64}@)
 
[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*
@ (?:(?=[a-z0-9-]{1,63}\.)[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+
  
(?=[a-z0-9-]{1,63}\z)[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\z

したがって、公式規格に従っていても、トレードオフが存在します。オンラインライブラリやディスカッションフォーラムから正規表現を盲目的にコピーしないでください。常に独自のデータとアプリケーションでテストしてください。