判断是否是电话号码

使用正则表达式验证中国大陆手机号码格式的有效性

问题

在前端开发中,我们经常需要验证用户输入的手机号码是否合法。这道题要求实现一个函数,判断给定的字符串是否符合中国大陆手机号码的格式规则。

中国大陆手机号码的基本规则:

  • 由 11 位数字组成
  • 以 1 开头
  • 第二位通常是 3-9 之间的数字
  • 常见号段:13x, 14x, 15x, 16x, 17x, 18x, 19x

解答

/**
 * 判断是否是有效的手机号码
 * @param {string} phone - 待验证的手机号码
 * @returns {boolean} - 是否为有效手机号码
 */
function isPhoneNumber(phone) {
  // 基础版本:验证 11 位数字,1 开头
  const basicPattern = /^1\d{10}$/;
  
  // 严格版本:验证具体号段
  const strictPattern = /^1[3-9]\d{9}$/;
  
  // 更严格版本:验证常见运营商号段
  const detailedPattern = /^1(3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[0-35-9])\d{8}$/;
  
  // 类型检查
  if (typeof phone !== 'string') {
    return false;
  }
  
  // 去除空格和横线
  const cleanPhone = phone.replace(/[\s-]/g, '');
  
  // 使用严格模式验证
  return strictPattern.test(cleanPhone);
}

/**
 * 判断是否是有效的手机号码(详细版本)
 * @param {string} phone - 待验证的手机号码
 * @param {boolean} strict - 是否使用严格模式(验证具体号段)
 * @returns {boolean} - 是否为有效手机号码
 */
function isValidPhone(phone, strict = false) {
  if (typeof phone !== 'string') {
    return false;
  }
  
  // 清理输入:去除空格、横线、括号等
  const cleanPhone = phone.replace(/[\s\-()]/g, '');
  
  if (strict) {
    // 严格模式:验证具体运营商号段
    // 中国移动:134-139, 147, 150-152, 157-159, 165, 172, 178, 182-184, 187-188, 198
    // 中国联通:130-132, 145, 155-156, 166, 171, 175-176, 185-186
    // 中国电信:133, 149, 153, 173, 177, 180-181, 189, 191, 199
    // 虚拟运营商:170
    const strictPattern = /^1(3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[0-35-9])\d{8}$/;
    return strictPattern.test(cleanPhone);
  } else {
    // 宽松模式:只验证基本格式
    const basicPattern = /^1[3-9]\d{9}$/;
    return basicPattern.test(cleanPhone);
  }
}

使用示例

// 基础使用
console.log(isPhoneNumber('13812345678')); // true
console.log(isPhoneNumber('12812345678')); // false (第二位不是3-9)
console.log(isPhoneNumber('138123456789')); // false (超过11位)
console.log(isPhoneNumber('1381234567')); // false (少于11位)

// 带格式的号码
console.log(isPhoneNumber('138 1234 5678')); // true (自动去除空格)
console.log(isPhoneNumber('138-1234-5678')); // true (自动去除横线)

// 使用详细版本
console.log(isValidPhone('13812345678')); // true
console.log(isValidPhone('13812345678', true)); // true (严格模式)
console.log(isValidPhone('138 1234 5678')); // true
console.log(isValidPhone('(138) 1234-5678')); // true

// 错误情况
console.log(isValidPhone('11812345678')); // false (第二位是1)
console.log(isValidPhone('abc12345678')); // false (包含字母)
console.log(isValidPhone(13812345678)); // false (不是字符串)
console.log(isValidPhone('')); // false (空字符串)
console.log(isValidPhone(null)); // false (null值)

// 实际应用场景
function validatePhoneInput(input) {
  if (!isValidPhone(input)) {
    return {
      valid: false,
      message: '请输入有效的手机号码'
    };
  }
  return {
    valid: true,
    message: '手机号码格式正确',
    phone: input.replace(/[\s\-()]/g, '')
  };
}

console.log(validatePhoneInput('138 1234 5678'));
// { valid: true, message: '手机号码格式正确', phone: '13812345678' }

关键点

  • 正则表达式模式/^1[3-9]\d{9}$/ 是最常用的验证模式

    • ^ 表示字符串开始
    • 1 表示必须以1开头
    • [3-9] 表示第二位是3到9之间的数字
    • \d{9} 表示后面跟9个数字
    • $ 表示字符串结束
  • 输入清理:使用 replace(/[\s-]/g, '') 去除空格和横线,提升用户体验

  • 类型检查:验证输入是否为字符串类型,避免类型错误

  • 灵活性设计:提供宽松模式和严格模式两种验证方式,适应不同场景需求

  • 号段更新:手机号段会随时间更新,严格模式的正则需要定期维护

  • 性能考虑:正则表达式验证性能较好,适合高频调用场景

  • 边界情况处理:考虑空字符串、null、undefined 等特殊输入