如何使用CAtlRegExp使用C ++验证电子邮件地址

时间:2017-05-05 18:33:36

标签: c++ regex atl email-address

我需要能够在C ++中验证各种格式的国际电子邮件地址。我发现网上的许多答案都没有删除,我找到了一个适合我的解决方案,我认为我会为使用ATL Server Library的任何人分享

一些背景知识。我从这篇文章开始:Using a regular expression to validate an email address。其中指出http://emailregex.com/具有支持RFC 5322 Official Standard互联网消息传递格式的各种语言的正则表达式。

提供的正则表达式是

  

(在[a-Z0-9#$%&安培;' + / = ^ _`{|}〜! - ?] +(?:[A-Z0-9?! #$%&安培;' + / = ^ _`{|}〜 - ] +) |"(?:[\ x01- \ X08 \ X0B \ X0C \? x0e- \ X1F \ X21 \ x23- \ x5b \ x5d- \ 0x7F部分] | \ [\ x01- \ X09 \ X0B \ X0C \ x0e- \ 0x7F部分])&#34)@(:(? ?:????一个-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- \ 0x7F部分] | \ [\ x01- \ X09 \ X0B \ X0C \ x0e- \ 0x7F部分])+)])

我正在使用带有ATL Server Library的C ++,这曾经曾经是Visual Studio的一部分。微软此后将其作为开源的CodePlex。我们仍然将它用于某些模板库。我的目标是修改此正则表达式,使其适用于CAtlRegEx

1 个答案:

答案 0 :(得分:1)

ATL中的正则表达式引擎(CAtlRegExp)非常基本。我能够修改正则表达式如下:

  

^ {([A-Z0-9#$%&安培;'!? + / = ^ _`{|}〜\ - ]。+(\([A-Z0-9 !#$%&安培;'?。 + / = ^ _`{|}〜\ - ] +))*)@(((A-Z0-9 \)+α-Z0 -9)?|(\ [(((2 - ((5 [0-5])|([0-4] [0-9])))|(1 [0-9] [0-9]) |([1-9] [0-9]))\)(((2 - ((5 [0-5])|([0-4] [0-9])))|(1 [ 0-9] [0-9])|([1-9] [0-9]))\)(((2 - ((5 [0-5])|?([0-4] [0 -9])))|(1 [0-9] [0-9])|?([1-9] [0-9]))\)((2((5- [0-5]) |([0-4] [0-9])))|(1 [0-9] [0-9])|?([1-9] [0-9]))\]))} $

似乎唯一丢失的是域名中的Unicode支持,我可以通过使用How to: Verify that Strings Are in Valid Email Format按照MSDN上IdnToAscii文章中的C#示例来解决这个问题。

在此方法中,从电子邮件地址中提取用户名和域名。使用IdnToAscii将域名转换为Ascii,然后将两者重新组合在一起,然后运行正则表达式。

请注意,为了便于阅读,省略了错误处理。需要代码以确保没有缓冲区溢出和其他错误处理。传递超过255个字符的电子邮件地址的人将导致此示例崩溃。

代码:

bool WINAPI LocalLooksLikeEmailAddress(LPCWSTR lpszEmailAddress) 
{
    bool bRetVal = true ;
    const int ccbEmailAddressMaxLen = 255 ;
    wchar_t achANSIEmailAddress[ccbEmailAddressMaxLen] = { L'\0' } ;
    ATL::CAtlRegExp<> regexp ;
    ATL::CAtlREMatchContext<> regexpMatch ;
    ATL::REParseError status  = regexp.Parse(L"^{.+}@{.+}$", FALSE) ;
    if (status == REPARSE_ERROR_OK) {
        if (regexp.Match(lpszEmailAddress, &regexpMatch) && regexpMatch.m_uNumGroups == 2) {
            const CAtlREMatchContext<>::RECHAR* szStart = 0 ;
            const CAtlREMatchContext<>::RECHAR* szEnd   = 0 ;
            regexpMatch.GetMatch(0, &szStart, &szEnd) ;
            ::wcsncpy_s(achANSIEmailAddress, szStart, (size_t)(szEnd - szStart)) ;
            regexpMatch.GetMatch(1, &szStart, &szEnd) ;
            wchar_t achDomainName[ccbEmailAddressMaxLen] = { L'\0' } ;
            ::wcsncpy_s(achDomainName, szStart, (size_t)(szEnd - szStart)) ;

            if (bRetVal) {
                wchar_t achPunycode[ccbEmailAddressMaxLen] = { L'\0' } ;
                if (IdnToAscii(0, achDomainName, -1, achPunycode, ccbEmailAddressMaxLen) == 0)
                    bRetVal = false ;
                else {
                    ::wcscat_s(achANSIEmailAddress, L"@") ;
                    ::wcscat_s(achANSIEmailAddress, achPunycode) ;
                }
            }
        }
    } 

    if (bRetVal) {
        status = regexp.Parse(
            L"^{([a-z0-9!#$%&'*+/=?^_`{|}~\\-]+(\\.([a-z0-9!#$%&'*+/=?^_`{|}~\\-]+))*)@((([a-z0-9]([a-z0-9\\-]*[a-z0-9])?\\.)+[a-z0-9]([a-z0-9\\-]*[a-z0-9])?)|(\\[(((2((5[0-5])|([0-4][0-9])))|(1[0-9][0-9])|([1-9]?[0-9]))\\.)(((2((5[0-5])|([0-4][0-9])))|(1[0-9][0-9])|([1-9]?[0-9]))\\.)(((2((5[0-5])|([0-4][0-9])))|(1[0-9][0-9])|([1-9]?[0-9]))\\.)((2((5[0-5])|([0-4][0-9])))|(1[0-9][0-9])|([1-9]?[0-9]))\\]))}$"
            , FALSE) ;
        if (status == REPARSE_ERROR_OK) {
            bRetVal = regexp.Match(achANSIEmailAddress, &regexpMatch) != 0;
        } 
    }

    return bRetVal ;
}

值得一提的是,这种方法与两个电子邮件地址的C#MSDN article中的结果不一致。查看http://emailregex.com上列出的原始正则表达式表明MSDN Article错误,除非最近更改了规范。我决定使用http://emailregex.com

中提到的正则表达式

我的单元测试使用MSDN Article

中的相同电子邮件地址
#include <Windows.h>
#if _DEBUG
#define TESTEXPR(expr) _ASSERTE(expr)
#else
#define TESTEXPR(expr) if (!(expr)) throw ;
#endif

void main()
{
    LPCWSTR validEmailAddresses[] = {   L"david.jones@proseware.com", 
                                        L"d.j@server1.proseware.com",
                                        L"jones@ms1.proseware.com", 
                                        L"j@proseware.com9", 
                                        L"js#internal@proseware.com",
                                        L"j_9@[129.126.118.1]", 
                                        L"js*@proseware.com",            // <== according to https://msdn.microsoft.com/en-us/library/01escwtf(v=vs.110).aspx this is invalid
                                                                         // but according to http://emailregex.com/ that claims to support the RFC 5322 Official standard it's not. 
                                                                         // I'm going with valid
                                        L"js@proseware.com9", 
                                        L"j.s@server1.proseware.com",
                                        L"js@contoso.中国", 
                                        NULL } ;

    LPCWSTR invalidEmailAddresses[] = { L"j.@server1.proseware.com",
                                        L"\"j\\\"s\\\"\"@proseware.com", // <== according to https://msdn.microsoft.com/en-us/library/01escwtf(v=vs.110).aspx this is valid
                                                                         // but according to http://emailregex.com/ that claims to support the RFC 5322 Official standard it's not. 
                                                                         // I'm going with Invalid
                                        L"j..s@proseware.com",
                                        L"js@proseware..com",
                                        NULL } ;

    for (LPCWSTR* emailAddress = validEmailAddresses ; *emailAddress != NULL ; ++emailAddress)
    {
        TESTEXPR(LocalLooksLikeEmailAddress(*emailAddress)) ;
    }
    for (LPCWSTR* emailAddress = invalidEmailAddresses ; *emailAddress != NULL ; ++emailAddress)
    {
        TESTEXPR(!LocalLooksLikeEmailAddress(*emailAddress)) ;
    }
}