手機號驗證是表單校驗、用戶註冊、短信發送等場景的高頻需求。中國大陸手機號遵循「11 位數字、首位 1、第二位 3-9、第三位依運營商規則」的結構。本文提供生產就緒的正則模式,涵蓋通用、移動、聯通、電信、固話/小靈通五大場景。
public interface RegexpConst {
/** 通用手機號:三大運營商全覆蓋 */
String MOBILE = "^1(3[0-9]|5[0-35-9]|8[025-9])\\d{8}$";
/** 中國移動:134-139、147、150-152、157-159、172、178、182-184、187-188、198 */
String CM = "^1(34[0-8]|(3[5-9]|5[017-9]|8[23478])\\d)\\d{7}$";
/** 中國聯通:130-132、145、155、156、166、171、175、176、185、186、196 */
String CU = "^1(3[0-2]|5[56]|8[56])\\d{8}$";
/** 中國電信:133、149、153、173、177、180、181、189、199 */
String CT = "^1((33|53|8[019])[0-9]|349|7[37])\\d{7}$";
/** 固話/小靈通:區號 3-4 位 (010/021/0xxx) + 號碼 7-8 位 */
String PHS = "^0(10|2[0-5789]|\\d{3})\\d{7,8}$";
}
MOBILE^1 # 首位固定 1
( # 第二、三位分組
3[0-9] # 130-139 全段
| 5[0-35-9] # 150-153, 155-159 (排除 154)
| 8[025-9] # 180, 182-189 (排除 181)
)
\\d{8}$ # 後 8 位任意數字
覆蓋率:包含 13x、15x、18x 全段,以及 147、176、177、181、189、191、198、199 等新號段 (視具體版本)。建議定期同步工信部最新號段資料更新正則。
| 運營商 | 核心號段 (第二、三位) | 正則關鍵部分 |
|---|---|---|
| 移動 | 134-139, 147, 150-152, 157-159, 172, 178, 182-184, 187-188, 198 | 34[0-8]|(3[5-9]|5[017-9]|8[23478]) |
| 聯通 | 130-132, 145, 155-156, 166, 171, 175-176, 185-186, 196 | 3[0-2]|5[56]|8[56] |
| 電信 | 133, 149, 153, 173, 177, 180-181, 189, 199 | (33|53|8[019])|349|7[37] |
import java.util.regex.Pattern;
public class MobileValidator {
private static final Pattern MOBILE_PATTERN = Pattern.compile(RegexpConst.MOBILE);
private static final Pattern CM_PATTERN = Pattern.compile(RegexpConst.CM);
private static final Pattern CU_PATTERN = Pattern.compile(RegexpConst.CU);
private static final Pattern CT_PATTERN = Pattern.compile(RegexpConst.CT);
private static final Pattern PHS_PATTERN = Pattern.compile(RegexpConst.PHS);
/** 靜態編譯 Pattern,效能最佳 */
public static boolean isMobile(String phone) {
return phone != null && MOBILE_PATTERN.matcher(phone).matches();
}
public static boolean isChinaMobile(String phone) {
return phone != null && CM_PATTERN.matcher(phone).matches();
}
public static boolean isChinaUnicom(String phone) {
return phone != null && CU_PATTERN.matcher(phone).matches();
}
public static boolean isChinaTelecom(String phone) {
return phone != null && CT_PATTERN.matcher(phone).matches();
}
public static boolean isLandline(String phone) {
return phone != null && PHS_PATTERN.matcher(phone).matches();
}
/** 識別運營商類型 */
public static String getCarrier(String phone) {
if (!isMobile(phone)) return "UNKNOWN";
if (isChinaMobile(phone)) return "CHINA_MOBILE";
if (isChinaUnicom(phone)) return "CHINA_UNICOM";
if (isChinaTelecom(phone)) return "CHINA_TELECOM";
return "OTHER";
}
}
@Test
void testMobileValidation() {
// 正向用例
assertTrue(MobileValidator.isMobile("13800138000"));
assertTrue(MobileValidator.isMobile("15912345678"));
assertTrue(MobileValidator.isMobile("18612345678"));
assertEquals("CHINA_MOBILE", MobileValidator.getCarrier("13900000000"));
assertEquals("CHINA_UNICOM", MobileValidator.getCarrier("13100000000"));
assertEquals("CHINA_TELECOM", MobileValidator.getCarrier("13300000000"));
// 反向用例
assertFalse(MobileValidator.isMobile("12800138000")); // 第二位不合法
assertFalse(MobileValidator.isMobile("1380013800")); // 10 位
assertFalse(MobileValidator.isMobile("138001380000")); // 12 位
assertFalse(MobileValidator.isMobile("abc")); // 非數字
assertNull(MobileValidator.isMobile(null)); // null 安全
}
libphonenumber (Google 開源庫) 替代手寫正則。libphonenumber 企業級方案<dependency>
<groupId>com.googlecode.libphonenumber</groupId>
<artifactId>libphonenumber</artifactId>
<version>8.13.0</version>
</dependency>
// 使用示例
PhoneNumberUtil util = PhoneNumberUtil.getInstance();
Phonenumber.PhoneNumber pn = util.parse("13800138000", "CN");
boolean valid = util.isValidNumber(pn); // true
String formatted = util.format(pn, PhoneNumberFormat.E164); // +8613800138000
支援 200+ 國家/地區、號碼類型識別 (行動/固話/免費/付費/VoIP)、格式化、地理位置推斷,是國際化產品的標準選擇。
正則驗證雖簡單,但號段演進快、邊界情況多,建立可維護的驗證體系 (常量管理、靜態編譯、單元測試、定期更新機制) 才是長久之計。