作法:確認字串是否為有效的電子郵件格式How to: Verify that Strings Are in Valid Email Format

下列範例會使用規則運算式來確認字串是否為有效的電子郵件格式。The following example uses a regular expression to verify that a string is in valid email format.

範例Example

此範例會定義 IsValidEmail 方法,如果字串包含有效的電子郵件地址,則這個方法會傳回 true ,否則會傳回 false ,但不會採取其他任何動作。The example defines an IsValidEmail method, which returns true if the string contains a valid email address and false if it does not, but takes no other action.

為了驗證電子郵件地址是否有效, IsValidEmail 方法會以 Regex.Replace(String, String, MatchEvaluator) 規則運算式模式呼叫 (@)(.+)$ 方法,從電子郵件地址分離出網域名稱。To verify that the email address is valid, the IsValidEmail method calls the Regex.Replace(String, String, MatchEvaluator) method with the (@)(.+)$ regular expression pattern to separate the domain name from the email address. 第三個參數是 MatchEvaluator 委派,用於表示處理並取代相符文字的方法。The third parameter is a MatchEvaluator delegate that represents the method that processes and replaces the matched text. 規則運算式模式解譯如下。The regular expression pattern is interpreted as follows.

模式Pattern 說明Description
(@) 比對 @ 字元。Match the @ character. 這是第一個擷取群組。This is the first capturing group.
(.+) 比對出現一次或多次的任何字元。Match one or more occurrences of any character. 這是第二個擷取群組。This is the second capturing group.
$ 在字串的結尾結束比對。End the match at the end of the string.

網域名稱會連同 @ 字元一併傳遞至 DomainMapper 方法,該方法會使用 IdnMapping 類別將 US-ASCII 字元範圍以外的 Unicode 字元轉譯為 Punycode。The domain name along with the @ character is passed to the DomainMapper method, which uses the IdnMapping class to translate Unicode characters that are outside the US-ASCII character range to Punycode. 如果 invalid 方法在網域名稱中偵測到任何無效字元,則方法也會將 True 旗標設定為 IdnMapping.GetAsciiThe method also sets the invalid flag to True if the IdnMapping.GetAscii method detects any invalid characters in the domain name. 方法會將前面加上 @ 符號的 Punycode 網域名稱傳回至 IsValidEmail 方法。The method returns the Punycode domain name preceded by the @ symbol to the IsValidEmail method.

接著 IsValidEmail 方法會呼叫 Regex.IsMatch(String, String) 方法,確認位址符合規則運算式模式。The IsValidEmail method then calls the Regex.IsMatch(String, String) method to verify that the address conforms to a regular expression pattern.

請注意, IsValidEmail 方法並不會驗證電子郵件地址的真實性。Note that the IsValidEmail method does not perform authentication to validate the email address. 它只會判斷電子郵件地址的格式是否有效。It merely determines whether its format is valid for an email address. 此外, IsValidEmail 方法不會驗證最上層網域名稱是否為 IANA 根區域資料庫列出的有效網域名稱,這項驗證需要執行查閱作業。In addition, the IsValidEmail method does not verify that the top-level domain name is a valid domain name listed at the IANA Root Zone Database, which would require a look-up operation. 規則運算式只會驗證最上層網域名稱是否包含介於 2 到 24 個英數 ASCII 字元,且第一個和最後一個為英數字元,而其餘字元為英數字元或連字號 (-)。Instead, the regular expression merely verifies that the top-level domain name consists of between two and twenty-four ASCII characters, with alphanumeric first and last characters and the remaining characters being either alphanumeric or a hyphen (-).

using System;
using System.Globalization;
using System.Text.RegularExpressions;

public class RegexUtilities
{
    public static bool IsValidEmail(string email)
    {
        if (string.IsNullOrWhiteSpace(email))
            return false;

        try
        {
            // Normalize the domain
            email = Regex.Replace(email, @"(@)(.+)$", DomainMapper,
                                  RegexOptions.None, TimeSpan.FromMilliseconds(200));

            // Examines the domain part of the email and normalizes it.
            string DomainMapper(Match match)
            {
                // Use IdnMapping class to convert Unicode domain names.
                var idn = new IdnMapping();

                // Pull out and process domain name (throws ArgumentException on invalid)
                var domainName = idn.GetAscii(match.Groups[2].Value);

                return match.Groups[1].Value + domainName;
            }
        }
        catch (RegexMatchTimeoutException e)
        {
            return false;
        }
        catch (ArgumentException e)
        {
            return false;
        }

        try
        {
            return Regex.IsMatch(email,
                @"^(?("")("".+?(?<!\\)""@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])@))" +
                @"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-0-9a-z]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$",
                RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250));
        }
        catch (RegexMatchTimeoutException)
        {
            return false;
        }
    }
}
Imports System.Globalization
Imports System.Text.RegularExpressions

Public Class RegexUtilities

    Public Shared Function IsValidEmail(email As String) As Boolean

        If String.IsNullOrWhiteSpace(email) Then Return False

        ' Use IdnMapping class to convert Unicode domain names.
        Try
            'Examines the domain part of the email and normalizes it.
            Dim DomainMapper =
                Function(match As Match) As String

                    'Use IdnMapping class to convert Unicode domain names.
                    Dim idn = New IdnMapping

                    'Pull out and process domain name (throws ArgumentException on invalid)
                    Dim domainName As String = idn.GetAscii(match.Groups(2).Value)

                    Return match.Groups(1).Value & domainName
                    
                End Function

            'Normalize the domain
            email = Regex.Replace(email, "(@)(.+)$", DomainMapper,
                                  RegexOptions.None, TimeSpan.FromMilliseconds(200))

        Catch e As RegexMatchTimeoutException
            Return False

        Catch e As ArgumentException
            Return False

        End Try

        Try
            Return Regex.IsMatch(email,
                                 "^(?("")("".+?(?<!\\)""@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])@))" +
                                 "(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-0-9a-z]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$",
                                 RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250))

        Catch e As RegexMatchTimeoutException
            Return False

        End Try

    End Function

End Class

在這個範例中,規則運算式模式 ^(?(")(".+?(?<!\\)"@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`{}|~\w])*)(?<=[0-9a-z])@))(?([)([(\d{1,3}.){3}\d{1,3}])|(([0-9a-z][-0-9a-z]*[0-9a-z]*.)+[a-z0-9][-a-z0-9]{0,22}[a-z0-9]))$ 會依下表所示的方式解譯。In this example, the regular expression pattern ^(?(")(".+?(?<!\\)"@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`{}|~\w])*)(?<=[0-9a-z])@))(?([)([(\d{1,3}.){3}\d{1,3}])|(([0-9a-z][-0-9a-z]*[0-9a-z]*.)+[a-z0-9][-a-z0-9]{0,22}[a-z0-9]))$ is interpreted as shown in the following table. 請注意,規則運算式是使用 RegexOptions.IgnoreCase 旗標所編譯。Note that the regular expression is compiled using the RegexOptions.IgnoreCase flag.

模式Pattern 說明Description
^ 在字串開頭開始比對。Begin the match at the start of the string.
(?(") 判斷第一個字元是否為引號。Determine whether the first character is a quotation mark. (?(") 是交替建構的開頭。(?(") is the beginning of an alternation construct.
(?("")("".+?(?<!\\)""@) 如果第一個字元是引號,則比對是否為開頭引號後面至少接著一個任何字元,然後再接著結尾引號。If the first character is a quotation mark, match a beginning quotation mark followed by at least one occurrence of any character, followed by an ending quotation mark. 結尾引號前面絕不能是反斜線字元 (\) 。The ending quotation mark must not be preceded by a backslash character (\). (?<! 是零寬度左不合樣 (Negative Lookbehind) 判斷提示的開頭。(?<! is the beginning of a zero-width negative lookbehind assertion. 此字串應該以 @ 記號做為結束。The string should conclude with an at sign (@).
|(([0-9a-z] 如果第一個字元不是引號,則比對 a 到 z 或 A 到 Z 的任何字母字元 (此比較不區分大小寫) 或 0 到 9 的任何數字字元。If the first character is not a quotation mark, match any alphabetic character from a to z or A to Z (the comparison is case insensitive), or any numeric character from 0 to 9.
(\.(?!\.)) 如果下一個字元是句號,則相符。If the next character is a period, match it. 如果不是句號,則向右合樣下一個字元並繼續比對。If it is not a period, look ahead to the next character and continue the match. (?!\.) 是零寬度的右不合樣 (Negative Lookahead) 判斷提示,可防止電子郵件地址的本機部分出現兩個連續的句號。(?!\.) is a zero-width negative lookahead assertion that prevents two consecutive periods from appearing in the local part of an email address.
|[-!#$%&'*+/=?^`{}|~\w] 如果下一個字元不是句號,則比對任何文字字元或下列其中一個字元:-!#$%'*+=?^`{}|~。If the next character is not a period, match any word character or one of the following characters: -!#$%'*+=?^`{}|~.
((.(?!.))|[-!#$%'*+/=?^`{}|~\w])* 比對交替模式 (句號後面接著非句號,或某個字元) 零次以上。Match the alternation pattern (a period followed by a non-period, or one of a number of characters) zero or more times.
@ 比對 @ 字元。Match the @ character.
(?<=[0-9a-z]) 如果位於 @ 字元前面的字元是 A 到 Z、a 到 z 或 0 到 9,則繼續比對。Continue the match if the character that precedes the @ character is A through Z, a through z, or 0 through 9. (?<=[0-9a-z]) 建構可定義零寬度的左合樣 (Positive Lookbehind) 判斷提示。The (?<=[0-9a-z]) construct defines a zero-width positive lookbehind assertion.
(?(\[) 檢查 @ 後面的字元是否為左括號。Check whether the character that follows @ is an opening bracket.
(\[(\d{1,3}\.){3}\d{1,3}\]) 如果是左括號,則比對左括號後面是否接著 IP 位址 (四組 1 至 3 位數的數字,而每組數字均以句號隔開) 與右括號。If it is an opening bracket, match the opening bracket followed by an IP address (four sets of one to three digits, with each set separated by a period) and a closing bracket.
|(([0-9a-z][-0-9a-z][0-9a-z].)+ 如果 @ 後面的字元不是左括號,則比對一個值為 A-Z、a-z 或 0-9 的英數字元,該英數字元後面接著零或多個連字號,再接著值為 A-Z、a-z 或 0-9 的零或一個英數字元,最後接著句點。If the character that follows @ is not an opening bracket, match one alphanumeric character with a value of A-Z, a-z, or 0-9, followed by zero or more occurrences of a hyphen, followed by zero or one alphanumeric character with a value of A-Z, a-z, or 0-9, followed by a period. 此模式可以重複一或多次,且後面必須接最上層網域名稱。This pattern can be repeated one or more times, and must be followed by the top-level domain name.
[a-z0-9][\-a-z0-9]{0,22}[a-z0-9])) 最上層網域名稱必須以英數字元 (a-z、A-Z 和 0-9) 開頭和結尾。The top-level domain name must begin and end with an alphanumeric character (a-z, A-Z, and 0-9). 其中也可以包含零到 22 個 ASCII 字元,英數字元或連字號皆可。It can also include from zero to 22 ASCII characters that are either alphanumeric or hyphens.
$ 在字串的結尾結束比對。End the match at the end of the string.

編譯程式碼Compiling the Code

IsValidEmailDomainMapper 方法可以包含在規則運算式公用程式方法的程式庫中,或是做為私用的靜態或執行個體方法包含在應用程式類別中。The IsValidEmail and DomainMapper methods can be included in a library of regular expression utility methods, or they can be included as private static or instance methods in the application class.

您也可以使用 Regex.CompileToAssembly 方法,將此規則運算式包含在規則運算式程式庫中。You can also use the Regex.CompileToAssembly method to include this regular expression in a regular expression library.

如果它們是在規則運算式程式庫中使用,則可以使用像是下列程式碼呼叫它們:If they are used in a regular expression library, you can call them by using code such as the following:

class Program
{
    static void Main(string[] args)
    {
        string[] emailAddresses = { "david.jones@proseware.com", "d.j@server1.proseware.com",
                                    "jones@ms1.proseware.com", "j.@server1.proseware.com",
                                    "j@proseware.com9", "js#internal@proseware.com",
                                    "j_9@[129.126.118.1]", "j..s@proseware.com",
                                    "js*@proseware.com", "js@proseware..com",
                                    "js@proseware.com9", "j.s@server1.proseware.com",
                                    "\"j\\\"s\\\"\"@proseware.com", "js@contoso.中国" };

        foreach (var emailAddress in emailAddresses)
        {
            if (RegexUtilities.IsValidEmail(emailAddress))
                Console.WriteLine($"Valid:   {emailAddress}");
            else
                Console.WriteLine($"Invalid: {emailAddress}");
        }

        Console.ReadKey();
    }
}
// The example displays the following output:
//       Valid: david.jones@proseware.com
//       Valid: d.j@server1.proseware.com
//       Valid: jones@ms1.proseware.com
//       Invalid: j.@server1.proseware.com
//       Valid: j@proseware.com9
//       Valid: js#internal@proseware.com
//       Valid: j_9@[129.126.118.1]
//       Invalid: j..s@proseware.com
//       Invalid: js*@proseware.com
//       Invalid: js@proseware..com
//       Valid: js@proseware.com9
//       Valid: j.s@server1.proseware.com
//       Valid: "j\"s\""@proseware.com
//       Valid: js@contoso.中国
Public Class Application
   Public Shared Sub Main()
      Dim emailAddresses() As String = {"david.jones@proseware.com", "d.j@server1.proseware.com",
                                       "jones@ms1.proseware.com", "j.@server1.proseware.com",
                                       "j@proseware.com9", "js#internal@proseware.com",
                                       "j_9@[129.126.118.1]", "j..s@proseware.com",
                                       "js*@proseware.com", "js@proseware..com",
                                       "js@proseware.com9", "j.s@server1.proseware.com",
                                       """j\""s\""""@proseware.com", "js@contoso.中国"}

      For Each emailAddress As String In emailAddresses
         If RegexUtilities.IsValidEmail(emailAddress) Then
               Console.WriteLine($"Valid:   {emailAddress}")
         Else
               Console.WriteLine($"Invalid: {emailAddress}")
         End If
      Next
   End Sub
End Class
' The example displays the following output:
'       Valid: david.jones@proseware.com
'       Valid: d.j@server1.proseware.com
'       Valid: jones@ms1.proseware.com
'       Invalid: j.@server1.proseware.com
'       Valid: j@proseware.com9
'       Valid: js#internal@proseware.com
'       Valid: j_9@[129.126.118.1]
'       Invalid: j..s@proseware.com
'       Invalid: js*@proseware.com
'       Invalid: js@proseware..com
'       Valid: js@proseware.com9
'       Valid: j.s@server1.proseware.com
'       Valid: "j\"s\""@proseware.com
'       Valid: js@contoso.中国

另請參閱See also