Механизм регулярных выражений (CAtlRegExp) в ATL довольно прост. Мне удалось изменить регулярное выражение следующим образом:
^{([a-z0-9!#$%&'+/=?^_`{|}~\-]+(\.([a-z0-9!#$%&'< /em>+/=?^_`{|}~\-]+))*)@(((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]))\]))}$
Единственное, что кажется потерянным, — это поддержка Unicode в доменных именах, которую я смог решить, следуя примеру C# в Как: проверить, что строки имеют допустимый формат электронной почты в статье на MSDN, написанной используя Иднтоаскии.
В этом подходе имя пользователя и доменное имя извлекаются из адреса электронной почты. Доменное имя преобразуется в ASCII с помощью IdnToAscii, а затем они снова соединяются вместе, а затем прогоняются через регулярное выражение.
Имейте в виду, что обработка ошибок была опущена для удобочитаемости. Код необходим, чтобы убедиться, что нет переполнения буфера и другой обработки ошибок. Если кто-то передаст адрес электронной почты длиной более 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, ®expMatch) && 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, ®expMatch) != 0;
}
}
return bRetVal ;
}
Стоит отметить, что этот подход не согласуется с результатами в C# Статья MSDN для двух адресов электронной почты. Глядя на исходное регулярное выражение, указанное на http://emailregex.com, можно предположить, что Статья MSDN ошибся, если спецификация не была недавно изменена. Я решил использовать регулярное выражение, упомянутое на http://emailregex.com.
Вот мои модульные тесты с использованием тех же адресов электронной почты из заголовка Статья MSDN
#include <Windows.h>
#if _DEBUG
#define TESTEXPR(expr) _ASSERTE(expr)
#else
#define TESTEXPR(expr) if (!(expr)) throw ;
#endif
void main()
{
LPCWSTR validEmailAddresses[] = { L"[email protected]",
L"[email protected]",
L"[email protected]",
L"[email protected]",
L"js#[email protected]",
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"[email protected]",
L"[email protected]",
L"js@contoso.中国",
NULL } ;
LPCWSTR invalidEmailAddresses[] = { L"[email protected]",
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"[email protected]",
L"[email protected]",
NULL } ;
for (LPCWSTR* emailAddress = validEmailAddresses ; *emailAddress != NULL ; ++emailAddress)
{
TESTEXPR(LocalLooksLikeEmailAddress(*emailAddress)) ;
}
for (LPCWSTR* emailAddress = invalidEmailAddresses ; *emailAddress != NULL ; ++emailAddress)
{
TESTEXPR(!LocalLooksLikeEmailAddress(*emailAddress)) ;
}
}
person
tdemay
schedule
05.05.2017