VC++手机号码验证两种常用写法:正则版和“无正则”的快速版,均适配中国大陆手机号
正则版(C++11)规则:可带可不带国家码 +86/86,可含空格/短横,核心号段 1[3-9] 开头共 11 位。 - #include <regex>
- #include <string>
- bool IsChinaMobileRegex(const std::string& s)
- {
- // 允许前后空白,可选 +86/86,可选分隔,核心为 1[3-9] 后 9 位
- static const std::regex re(
- R"(^\s*(?:\+?86[-\s]?)?1[3-9]\d{9}\s*$)"
- );
- return std::regex_match(s, re);
- }
复制代码 无正则快速版(更轻量,性能好)- 去掉前后空白
- 去掉空格和短横
- 去掉前缀 +86 或 86
- 核心校验:长度 11,首位为 '1',第二位 '3'~'9',其余全数字
- #include <string>
- #include <algorithm>
- #include <cctype>
- static inline void trim(std::string& s) {
- auto notsp = [](int ch){ return !std::isspace(ch); };
- s.erase(s.begin(), std::find_if(s.begin(), s.end(), notsp));
- s.erase(std::find_if(s.rbegin(), s.rend(), notsp).base(), s.end());
- }
- bool IsChinaMobileFast(std::string s)
- {
- trim(s);
- // 去掉分隔符(按需可扩展 '.' 等)
- s.erase(std::remove(s.begin(), s.end(), ' '), s.end());
- s.erase(std::remove(s.begin(), s.end(), '-'), s.end());
- // 去掉可选国家码
- if (s.rfind("+86", 0) == 0) s.erase(0, 3);
- else if (s.rfind("86", 0) == 0) s.erase(0, 2);
- if (s.size() != 11) return false;
- if (s[0] != '1') return false;
- if (s[1] < '3' || s[1] > '9') return false;
- return std::all_of(s.begin()+2, s.end(),
- [](unsigned char c){ return std::isdigit(c); });
- }
复制代码 CString 适配(MFC/ATL)
- #include <atlconv.h> // CT2A
- bool IsChinaMobileFast(const CString& cs)
- {
- CT2A a(cs);
- return IsChinaMobileFast(std::string(a));
- }
- // 或用正则版:IsChinaMobileRegex(std::string(a))
复制代码小提示 - 更严格的号段细分可用:1(3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[0-35-9]) 共 11 位;一般业务用 1[3-9]\d{9} 足够。
- 如果要拒绝前缀/分隔符,删掉相应的“去前缀/去分隔”代码即可。
只校验“纯11位中国大陆手机号”,不考虑+86、空格或短横。给出两个MFC版函数:一个通用简单规则,另一个更严格按号段判断。都用 CString,Unicode/ANSI 都可编译。 简单版:1[3-9]开头 + 剩余9位数字 - #include <atlstr.h>
- static inline bool IsDigitW(wchar_t ch) { return ch >= L'0' && ch <= L'9'; }
- bool IsCnMobile11_Simple(CString s)
- {
- s.Trim();
- if (s.GetLength() != 11) return false;
- #ifdef _UNICODE
- const wchar_t* p = s.GetString();
- #else
- const char* p = s.GetString();
- #endif
- // 全为数字
- for (int i = 0; i < 11; ++i) {
- #ifdef _UNICODE
- if (!IsDigitW(p[i])) return false;
- #else
- if (p[i] < '0' || p[i] > '9') return false;
- #endif
- }
- // 1 开头,第二位 3~9
- #ifdef _UNICODE
- if (p[0] != L'1') return false;
- return p[1] >= L'3' && p[1] <= L'9';
- #else
- if (p[0] != '1') return false;
- return p[1] >= '3' && p[1] <= '9';
- #endif
- }
复制代码严格版:按常见号段细分 - 13x、18x 全部允许
- 14[5-9]
- 15[0-35-9](排除154)
- 16[2567]
- 17[0-8]
- 19[0-35-9](常见做法:排除194)
- bool IsCnMobile11_Strict(CString s)
- {
- s.Trim();
- if (s.GetLength() != 11) return false;
- #ifdef _UNICODE
- const wchar_t* p = s.GetString();
- auto isDigit = [](wchar_t c){ return c >= L'0' && c <= L'9'; };
- #else
- const char* p = s.GetString();
- auto isDigit = [](char c){ return c >= '0' && c <= '9'; };
- #endif
- for (int i = 0; i < 11; ++i) if (!isDigit(p[i])) return false;
- #ifdef _UNICODE
- if (p[0] != L'1') return false;
- wchar_t b1 = p[1], b2 = p[2];
- #else
- if (p[0] != '1') return false;
- char b1 = p[1], b2 = p[2];
- #endif
- switch (b1) {
- case '3': return true; // 130-139
- case '4': return (b2 >= '5' && b2 <= '9'); // 145-149
- case '5': return (b2 != '4'); // 150-159(除154)
- case '6': return (b2=='2'||b2=='5'||b2=='6'||b2=='7'); // 162/165/166/167
- case '7': return (b2 >= '0' && b2 <= '8'); // 170-178
- case '8': return true; // 180-189
- case '9': return (b2 != '4'); // 常见做法:190-199(排194)
- default: return false;
- }
- }
复制代码 使用示例- CString phone = _T("13812345678");
- if (IsCnMobile11_Strict(phone)) {
- // 合法
- } else {
- // 非法
- }
复制代码说明 - 你只要纯11位数字时,优先用 Strict;若业务只需大范围校验,用 Simple 足够。
- 若需要进一步按照最新号段调整,只需要修改 switch 中各分支即可。
|