javascript正则表达式

58 阅读8分钟

javascript正则表达式

骚话王又来分享知识了!今天咱们聊聊前端开发中的正则表达式,这个让不少小伙伴又爱又恨的家伙。别看它长得像天书,掌握了基本API后,处理字符串那叫一个得心应手!

正则表达式的两种创建方式

在JavaScript中,咱们有两种方式来创建正则表达式,就像做菜有两种下锅方式一样。

字面量方式(推荐)

// 最常用的方式,简洁明了
const pattern = /hello/i;
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

构造函数方式

// 当你需要动态创建正则时才用这种
const pattern = new RegExp('hello', 'i');
const dynamicPattern = new RegExp(userInput, 'g');

两种方式各有千秋,字面量写起来简单,构造函数适合动态场景,该用哪个一目了然。

核心API方法大揭秘

test() - 最简单的真假判断

这货就是个布尔值制造机,问它"匹配不匹配?",它只会回答true或false。

const phonePattern = /^1[3-9]\d{9}$/;

console.log(phonePattern.test('13812345678')); // true
console.log(phonePattern.test('12345678901')); // false

// 验证邮箱格式
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (emailPattern.test(userEmail)) {
    console.log('邮箱格式正确,可以提交!');
} else {
    console.log('邮箱格式有问题,检查一下吧');
}

exec() - 详细信息搜集员

这个方法比test()更强大,不仅告诉你匹配没匹配,还把详细信息都给你列出来。

const pattern = /(\d{4})-(\d{2})-(\d{2})/;
const dateString = '今天是2024-03-15,天气不错';

const result = pattern.exec(dateString);
console.log(result);
// [
//   '2024-03-15',  // 完整匹配
//   '2024',        // 第一个分组
//   '03',          // 第二个分组  
//   '15',          // 第三个分组
//   index: 2,      // 匹配位置
//   input: '今天是2024-03-15,天气不错'
// ]

if (result) {
    const [fullMatch, year, month, day] = result;
    console.log(`年份:${year},月份:${month},日期:${day}`);
}

字符串的正则方法们

match() - 字符串的匹配高手
const text = '我的手机号是13812345678,备用号码是15987654321';
const phonePattern = /1[3-9]\d{9}/g;

const phones = text.match(phonePattern);
console.log(phones); // ['13812345678', '15987654321']

// 不加g标志,只返回第一个匹配
const firstPhone = text.match(/1[3-9]\d{9}/);
console.log(firstPhone[0]); // '13812345678'
replace() - 字符串改造专家

这个方法简直是字符串处理的瑞士军刀,能替换、能转换,功能那叫一个强大。

// 基础替换
const text = '你好,世界!Hello, World!';
const result = text.replace(/Hello/g, '你好');
console.log(result); // '你好,世界!你好, World!'

// 使用函数进行复杂替换
const sensitiveText = '我的电话是13812345678,QQ是123456789';
const hiddenText = sensitiveText.replace(/(\d{3})\d{4}(\d{4})/g, '$1****$2');
console.log(hiddenText); // '我的电话是138****5678,QQ是123456789'

// 回调函数替换,更灵活
const dateText = '2024-03-15';
const formattedDate = dateText.replace(/(\d{4})-(\d{2})-(\d{2})/, (match, year, month, day) => {
    return `${year}${month}${day}日`;
});
console.log(formattedDate); // '2024年03月15日'
search() - 位置查找器
const text = '学习JavaScript正则表达式';
const position = text.search(/正则/);
console.log(position); // 11

// 找不到返回-1
const notFound = text.search(/Python/);
console.log(notFound); // -1
split() - 字符串分割大师
// 基础分割
const csv = 'name,age,city';
const fields = csv.split(/,/);
console.log(fields); // ['name', 'age', 'city']

// 复杂分割
const text = '苹果,香蕉;橘子,葡萄;草莓';
const fruits = text.split(/[,;]/);
console.log(fruits); // ['苹果', '香蕉', '橘子', '葡萄', '草莓']

// 限制分割数量
const limited = text.split(/[,;]/, 3);
console.log(limited); // ['苹果', '香蕉', '橘子']

常用标志位详解

正则表达式的标志位就像调料一样,不同的搭配有不同的效果。

// g - 全局匹配,不加只匹配第一个
const globalMatch = 'abc abc abc'.replace(/abc/g, 'xyz'); // 'xyz xyz xyz'
const singleMatch = 'abc abc abc'.replace(/abc/, 'xyz');  // 'xyz abc abc'

// i - 忽略大小写
const caseInsensitive = /hello/i;
console.log(caseInsensitive.test('HELLO')); // true
console.log(caseInsensitive.test('Hello')); // true

// m - 多行模式
const multiline = /^start/m;
console.log(multiline.test('line1\nstart of line2')); // true

实战小技巧

表单验证一把梭

// 验证工具集合
const validators = {
    phone: /^1[3-9]\d{9}$/,
    email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
    idCard: /^\d{17}[\dXx]$/,
    password: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d@$!%*?&]{8,}$/
};

function validateForm(data) {
    const errors = [];
    
    if (!validators.phone.test(data.phone)) {
        errors.push('手机号格式不正确');
    }
    
    if (!validators.email.test(data.email)) {
        errors.push('邮箱格式不正确');
    }
    
    return errors.length === 0 ? null : errors;
}

文本清洗小能手

// 清除多余空格
function cleanText(text) {
    return text
        .replace(/\s+/g, ' ')        // 多个空格变一个
        .replace(/^\s+|\s+$/g, '');  // 去掉首尾空格
}

// 提取特定信息
function extractNumbers(text) {
    return text.match(/\d+/g) || [];
}

// 敏感信息脱敏
function maskSensitive(text) {
    return text
        .replace(/(\d{3})\d{4}(\d{4})/g, '$1****$2')     // 手机号
        .replace(/(\w{2})\w+(@\w+)/g, '$1****$2');       // 邮箱
}

经典案例

光说不练假把式,接下来咱们来看看一些实战中经常遇到的正则匹配案例。每个案例我都会掰开揉碎地给你讲解,保证你看完就能举一反三!

手机号码匹配

const phonePattern = /^1[3-9]\d{9}$/;

逐字符解析

  • ^ - 字符串开始标志,确保从头开始匹配
  • 1 - 必须以数字1开头(中国手机号特色)
  • [3-9] - 第二位数字必须是3到9之间的任意一个
  • \d - 匹配任意数字字符(等同于[0-9])
  • {9} - 前面的\d要重复9次
  • $ - 字符串结束标志,确保到此为止

使用示例

console.log(phonePattern.test('13812345678')); // true
console.log(phonePattern.test('12345678901')); // false (第二位是2)
console.log(phonePattern.test('138123456789')); // false (11位变12位了)

邮箱地址匹配

const emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;

逐字符解析

  • ^ - 开始标志
  • [a-zA-Z0-9._%+-] - 用户名部分可包含的字符集合
    • a-zA-Z - 大小写字母
    • 0-9 - 数字
    • ._%+- - 特殊字符点号、下划线、百分号、加号、减号
  • + - 前面的字符集至少出现1次
  • @ - 必须有@符号
  • [a-zA-Z0-9.-] - 域名部分字符集(字母数字点号减号)
  • + - 域名至少1个字符
  • \. - 转义的点号(因为.在正则中有特殊含义)
  • [a-zA-Z] - 顶级域名只能是字母
  • {2,} - 顶级域名至少2个字符

使用示例

console.log(emailPattern.test('user@example.com')); // true
console.log(emailPattern.test('test.email+tag@domain.co.uk')); // true
console.log(emailPattern.test('invalid.email')); // false (没有@)

身份证号匹配

const idCardPattern = /^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/;

这个看起来复杂,但咱们一点点拆解:

逐字符解析

  • ^[1-9] - 首位数字1-9(不能是0)
  • \d{5} - 接下来5位数字(地区码)
  • (18|19|20) - 年份前两位,只能是18、19或20
  • \d{2} - 年份后两位
  • (0[1-9]|1[0-2]) - 月份部分
    • 0[1-9] - 01到09月
    • 1[0-2] - 10到12月
  • (0[1-9]|[12]\d|3[01]) - 日期部分
    • 0[1-9] - 01到09日
    • [12]\d - 10到29日
    • 3[01] - 30到31日
  • \d{3} - 顺序码3位数字
  • [\dXx] - 校验码,可以是数字或X/x

URL网址匹配

const urlPattern = /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/;

逐字符解析

  • ^https? - 以http或https开头(?表示s可有可无)
  • :\/\/ - 冒号和两个转义的斜杠
  • (www\.)? - www.是可选的(?表示可有可无)
  • [-a-zA-Z0-9@:%._\+~#=]{1,256} - 域名主体部分,1到256个字符
  • \. - 转义的点号
  • [a-zA-Z0-9()]{1,6} - 顶级域名,1到6个字符
  • \b - 单词边界
  • ([-a-zA-Z0-9()@:%_\+.~#?&//=]*)- 路径参数部分(可选)

日期时间匹配

const datePattern = /^(\d{4})-(\d{2})-(\d{2})\s(\d{2}):(\d{2}):(\d{2})$/;

逐字符解析

  • ^(\d{4}) - 年份,4位数字,用括号分组
  • - - 连字符分隔符
  • (\d{2}) - 月份,2位数字分组
  • - - 连字符
  • (\d{2}) - 日期,2位数字分组
  • \s - 空白字符(空格)
  • (\d{2}) - 小时,2位数字分组
  • : - 冒号分隔符
  • (\d{2}) - 分钟,2位数字分组
  • : - 冒号
  • (\d{2}) - 秒数,2位数字分组

实用技巧

const dateString = '2024-03-15 14:30:25';
const match = dateString.match(datePattern);
if (match) {
    const [, year, month, day, hour, minute, second] = match;
    console.log(`${year}${month}${day}${hour}${minute}${second}秒`);
}

密码强度匹配

const strongPasswordPattern = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;

这个正则用了先行断言,比较高级:

逐字符解析

  • ^ - 开始标志
  • (?=.*[a-z]) - 先行断言,必须包含小写字母
  • (?=.*[A-Z]) - 先行断言,必须包含大写字母
  • (?=.*\d) - 先行断言,必须包含数字
  • (?=.*[@$!%*?&]) - 先行断言,必须包含特殊字符
  • [A-Za-z\d@$!%*?&]{8,} - 实际匹配8位以上的合法字符

中文字符匹配

const chinesePattern = /^[\u4e00-\u9fa5]+$/;

逐字符解析

  • ^ - 开始
  • [\u4e00-\u9fa5] - Unicode中文字符范围
  • + - 至少一个中文字符
  • $ - 结束

IP地址匹配

const ipPattern = /^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$/;

逐字符解析

  • (25[0-5]|2[0-4]\d|[01]?\d\d?) - 匹配0-255的数字
    • 25[0-5] - 250-255
    • 2[0-4]\d - 200-249
    • [01]?\d\d? - 0-199([01]?表示可选的0或1)
  • \. - 转义的点号
  • {3} - 前面的组合重复3次
  • 最后再来一个0-255的数字

实战应用函数

// 综合验证工具箱
const regexUtils = {
    // 验证手机号
    isPhone: (str) => /^1[3-9]\d{9}$/.test(str),
    
    // 验证邮箱
    isEmail: (str) => /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(str),
    
    // 验证身份证
    isIdCard: (str) => /^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/.test(str),
    
    // 提取所有数字
    extractNumbers: (str) => str.match(/\d+/g) || [],
    
    // 提取所有中文
    extractChinese: (str) => str.match(/[\u4e00-\u9fa5]+/g) || []
};

// 使用示例
console.log(regexUtils.isPhone('13812345678')); // true
console.log(regexUtils.extractNumbers('价格是128元')); // ['128']

银行卡号匹配

const bankCardPattern = /^[1-9]\d{12,18}$/;

逐字符解析

  • ^[1-9] - 首位不能是0,必须是1-9
  • \d{12,18} - 后面跟12到18位数字
  • $ - 结束标志

银行卡号一般是13-19位,这个正则覆盖了主流的卡号格式。

车牌号匹配

const licensePlatePattern = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-Z0-9]{5}$/;

逐字符解析

  • ^[京津沪...] - 省份简称,必须是指定的中文字符之一
  • [A-Z] - 地区代码,必须是大写字母
  • [A-Z0-9]{5} - 后面5位,可以是大写字母或数字
  • $ - 结束

使用示例

console.log(licensePlatePattern.test('京A12345')); // true
console.log(licensePlatePattern.test('粤B888AB')); // true
console.log(licensePlatePattern.test('aa12345')); // false (小写字母)

十六进制颜色代码匹配

const colorPattern = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;

逐字符解析

  • ^# - 必须以#开头
  • ([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}) - 两种格式之一
    • [A-Fa-f0-9]{6} - 6位十六进制(如#FF0000)
    • [A-Fa-f0-9]{3} - 3位十六进制(如#F00)
  • $ - 结束

使用示例

console.log(colorPattern.test('#FF0000')); // true (红色)
console.log(colorPattern.test('#f00')); // true (红色简写)
console.log(colorPattern.test('#GG0000')); // false (G不是十六进制)

版本号匹配

const versionPattern = /^(\d+)\.(\d+)\.(\d+)(-[a-zA-Z0-9]+)?$/;

逐字符解析

  • ^(\d+) - 主版本号,一个或多个数字,用括号分组
  • \. - 转义的点号
  • (\d+) - 次版本号分组
  • \. - 点号
  • (\d+) - 修订号分组
  • (-[a-zA-Z0-9]+)? - 可选的预发布标识
    • - - 连字符
    • [a-zA-Z0-9]+ - 字母数字组合
    • ? - 整个部分可选

使用示例

console.log(versionPattern.test('1.2.3')); // true
console.log(versionPattern.test('10.0.1-beta')); // true
console.log(versionPattern.test('2.1')); // false (缺少修订号)

HTML标签匹配

const htmlTagPattern = /<([a-zA-Z][a-zA-Z0-9]*)\b[^>]*>(.*?)<\/\1>/;

这个比较高级,用了反向引用:

逐字符解析

  • < - 左尖括号
  • ([a-zA-Z][a-zA-Z0-9]*) - 标签名分组
    • [a-zA-Z] - 必须以字母开头
    • [a-zA-Z0-9]* - 后面可以跟字母数字
  • \b - 单词边界
  • [^>]* - 属性部分,除了>的任意字符
  • > - 右尖括号
  • (.*?) - 标签内容,非贪婪匹配
  • <\/ - 结束标签开始
  • \1 - 反向引用第一个分组(标签名)
  • > - 结束标签的右尖括号

文件扩展名匹配

const imageFilePattern = /\.(jpg|jpeg|png|gif|bmp|webp)$/i;

逐字符解析

  • \. - 转义的点号
  • (jpg|jpeg|png|gif|bmp|webp) - 图片格式之一
  • $ - 字符串结尾
  • i - 忽略大小写标志

使用示例

console.log(imageFilePattern.test('avatar.jpg')); // true
console.log(imageFilePattern.test('photo.PNG')); // true (忽略大小写)
console.log(imageFilePattern.test('document.pdf')); // false

时间格式匹配(12小时制)

const time12Pattern = /^(0?[1-9]|1[0-2]):[0-5]\d\s?(AM|PM)$/i;

逐字符解析

  • ^(0?[1-9]|1[0-2]) - 小时部分
    • 0?[1-9] - 1-9,前面可选的0
    • 1[0-2] - 10-12
  • : - 冒号分隔符
  • [0-5]\d - 分钟,00-59
  • \s? - 可选的空格
  • (AM|PM) - 上午或下午标识
  • $ - 结束
  • i - 忽略大小写

社交媒体用户名匹配

const usernamePattern = /^[a-zA-Z0-9_]{3,16}$/;

逐字符解析

  • ^ - 开始
  • [a-zA-Z0-9_] - 只能包含字母、数字、下划线
  • {3,16} - 长度3到16位
  • $ - 结束

进阶版本(更严格)

const strictUsernamePattern = /^[a-zA-Z][a-zA-Z0-9_]{2,15}$/;

这个版本要求必须以字母开头,避免纯数字用户名。

网络端口号匹配

const portPattern = /^([1-9]\d{0,3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$/;

这个相当复杂,匹配1-65535的端口范围:

逐字符解析

  • [1-9]\d{0,3} - 1-9999
  • [1-5]\d{4} - 10000-59999
  • 6[0-4]\d{3} - 60000-64999
  • 65[0-4]\d{2} - 65000-65499
  • 655[0-2]\d - 65500-65529
  • 6553[0-5] - 65530-65535

简化版本

const simplePortPattern = /^([1-9]\d{0,4}|[1-5]\d{4}|6[0-5]{2}[0-3][0-5])$/;

综合应用实战

// 扩展版验证工具箱
const advancedRegexUtils = {
    // 基础验证
    isPhone: (str) => /^1[3-9]\d{9}$/.test(str),
    isEmail: (str) => /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(str),
    
    // 新增验证
    isBankCard: (str) => /^[1-9]\d{12,18}$/.test(str),
    isLicensePlate: (str) => /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-Z0-9]{5}$/.test(str),
    isColorCode: (str) => /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(str),
    isVersion: (str) => /^(\d+)\.(\d+)\.(\d+)(-[a-zA-Z0-9]+)?$/.test(str),
    isUsername: (str) => /^[a-zA-Z][a-zA-Z0-9_]{2,15}$/.test(str),
    
    // 提取功能
    extractColors: (str) => str.match(/#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/g) || [],
    extractUrls: (str) => str.match(/https?:\/\/[^\s]+/g) || [],
    extractEmails: (str) => str.match(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g) || [],
    
    // 格式化功能
    formatPhone: (str) => {
        const match = str.match(/^(\d{3})(\d{4})(\d{4})$/);
        return match ? `${match[1]}-${match[2]}-${match[3]}` : str;
    },
    
    maskBankCard: (str) => {
        return str.replace(/^(\d{4})(\d+)(\d{4})$/, '$1****$3');
    }
};

// 实战演示
const testData = {
    phone: '13812345678',
    bankCard: '6222081234567890123',
    color: '#FF5733',
    version: '2.1.0-beta',
    username: 'coder_2024'
};

console.log('手机号验证:', advancedRegexUtils.isPhone(testData.phone));
console.log('格式化手机号:', advancedRegexUtils.formatPhone(testData.phone));
console.log('银行卡脱敏:', advancedRegexUtils.maskBankCard(testData.bankCard));

邮政编码匹配

const zipCodePattern = /^[1-9]\d{5}$/;

逐字符解析

  • ^[1-9] - 首位不能是0,必须是1-9
  • \d{5} - 后面跟5位数字
  • $ - 结束标志

中国邮政编码是6位数字,首位不能为0。

座机号码匹配

const landlinePattern = /^0\d{2,3}-?\d{7,8}$/;

逐字符解析

  • ^0 - 必须以0开头
  • \d{2,3} - 区号2-3位数字
  • -? - 可选的连字符
  • \d{7,8} - 电话号码7-8位
  • $ - 结束

使用示例

console.log(landlinePattern.test('010-12345678')); // true
console.log(landlinePattern.test('02112345678')); // true (无连字符)
console.log(landlinePattern.test('400-123-4567')); // false (格式不对)

金额格式匹配

const moneyPattern = /^[1-9]\d*(\.\d{1,2})?$/;

逐字符解析

  • ^[1-9] - 整数部分首位不能是0
  • \d* - 整数部分可以有更多数字
  • (\.\d{1,2})? - 可选的小数部分
    • \. - 转义的点号
    • \d{1,2} - 1-2位小数
    • ? - 整个小数部分可选
  • $ - 结束

使用示例

console.log(moneyPattern.test('123.45')); // true
console.log(moneyPattern.test('1000')); // true
console.log(moneyPattern.test('0.99')); // false (整数部分不能是0)

域名匹配

const domainPattern = /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;

这个比较复杂,但很实用:

逐字符解析

  • ^[a-zA-Z0-9] - 域名必须以字母或数字开头
  • ([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])? - 中间部分
    • [a-zA-Z0-9-]{0,61} - 字母数字连字符,最多61个
    • [a-zA-Z0-9] - 必须以字母数字结尾
  • (\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)* - 子域名部分
  • $ - 结束

信用卡号匹配(Luhn算法验证)

const creditCardPattern = /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|3[0-9]{13}|6(?:011|5[0-9]{2})[0-9]{12})$/;

这个匹配主流信用卡格式:

逐字符解析

  • 4[0-9]{12}(?:[0-9]{3})? - Visa卡(13或16位)
  • 5[1-5][0-9]{14} - MasterCard(16位)
  • 3[47][0-9]{13} - American Express(15位)
  • 3[0-9]{13} - JCB(16位)
  • 6(?:011|5[0-9]{2})[0-9]{12} - Discover卡(16位)

数学表达式匹配

const mathExpressionPattern = /^(\d+(\.\d+)?[\+\-\*\/]\d+(\.\d+)?)+$/;

逐字符解析

  • ^ - 开始
  • (\d+(\.\d+)?[\+\-\*\/]\d+(\.\d+)?)+ - 数学表达式
    • \d+ - 一个或多个数字
    • (\.\d+)? - 可选的小数部分
    • [\+\-\*\/] - 四则运算符之一
    • 重复整个模式
  • $ - 结束

使用示例

console.log(mathExpressionPattern.test('1+2*3')); // true
console.log(mathExpressionPattern.test('10.5-3.2')); // true
console.log(mathExpressionPattern.test('abc+def')); // false

文件路径匹配

const filePathPattern = /^(\/|\.\/|\.\.\/)?([a-zA-Z0-9_-]+\/)*[a-zA-Z0-9_-]+(\.[a-zA-Z0-9]+)?$/;

逐字符解析

  • ^(\/|\.\/|\.\.\/)? - 可选的路径前缀
    • \/ - 绝对路径
    • \.\/ - 当前目录
    • \.\.\/ - 上级目录
  • ([a-zA-Z0-9_-]+\/)* - 目录部分,可以有多个
  • [a-zA-Z0-9_-]+ - 文件名
  • (\.[a-zA-Z0-9]+)? - 可选的扩展名
  • $ - 结束

网络MAC地址匹配

const macAddressPattern = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/;

逐字符解析

  • ^ - 开始
  • ([0-9A-Fa-f]{2}[:-]){5} - 前5组,每组2个十六进制字符加分隔符
    • [0-9A-Fa-f]{2} - 2个十六进制字符
    • [:-] - 冒号或连字符分隔符
    • {5} - 重复5次
  • ([0-9A-Fa-f]{2}) - 最后一组,2个十六进制字符
  • $ - 结束

使用示例

console.log(macAddressPattern.test('00:1B:44:11:3A:B7')); // true
console.log(macAddressPattern.test('00-1B-44-11-3A-B7')); // true
console.log(macAddressPattern.test('001B44113AB7')); // false (无分隔符)

时间戳匹配

const timestampPattern = /^\d{10,13}$/;

逐字符解析

  • ^ - 开始
  • \d{10,13} - 10到13位数字
    • 10位:秒级时间戳
    • 13位:毫秒级时间戳
  • $ - 结束

进阶版本(验证时间戳有效性)

const validTimestampPattern = /^(1[0-9]{9}|[2-9][0-9]{9}|1[0-9]{12}|[2-9][0-9]{12})$/;

哈希值匹配

const hashPattern = /^[a-fA-F0-9]{32,64}$/;

逐字符解析

  • ^ - 开始
  • [a-fA-F0-9] - 十六进制字符
  • {32,64} - 32到64位长度(MD5是32位,SHA256是64位)
  • $ - 结束

特定哈希算法匹配

const md5Pattern = /^[a-fA-F0-9]{32}$/;
const sha256Pattern = /^[a-fA-F0-9]{64}$/;
const sha1Pattern = /^[a-fA-F0-9]{40}$/;

特殊字符过滤

const specialCharPattern = /[<>\"'&]/g;

逐字符解析

  • [<>\"'&] - 匹配HTML特殊字符
    • < - 小于号
    • > - 大于号
    • \" - 双引号
    • ' - 单引号
    • & - 与号
  • g - 全局匹配

使用示例

const htmlText = '<script>alert("Hello")</script>';
const safeText = htmlText.replace(specialCharPattern, (match) => {
    const entities = {
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#39;',
        '&': '&amp;'
    };
    return entities[match];
});
console.log(safeText); // &lt;script&gt;alert(&quot;Hello&quot;)&lt;/script&gt;

高级文本处理工具

// 终极正则工具箱
const ultimateRegexUtils = {
    // 新增验证功能
    isZipCode: (str) => /^[1-9]\d{5}$/.test(str),
    isLandline: (str) => /^0\d{2,3}-?\d{7,8}$/.test(str),
    isMoney: (str) => /^[1-9]\d*(\.\d{1,2})?$/.test(str),
    isDomain: (str) => /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(str),
    isMacAddress: (str) => /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/.test(str),
    isTimestamp: (str) => /^\d{10,13}$/.test(str),
    isHash: (str) => /^[a-fA-F0-9]{32,64}$/.test(str),
    
    // 文本处理功能
    escapeHtml: (str) => str.replace(/[<>\"'&]/g, (match) => {
        const entities = { '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;', '&': '&amp;' };
        return entities[match];
    }),
    
    formatMoney: (str) => {
        const match = str.match(/^(\d+)(\.\d{1,2})?$/);
        if (match) {
            const integer = match[1].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
            return match[2] ? integer + match[2] : integer;
        }
        return str;
    },
    
    extractMathExpressions: (str) => str.match(/\d+(\.\d+)?[\+\-\*\/]\d+(\.\d+)?/g) || [],
    
    validateCreditCard: (str) => {
        // 移除空格和连字符
        const clean = str.replace(/[\s-]/g, '');
        if (!/^\d{13,19}$/.test(clean)) return false;
        
        // Luhn算法验证
        let sum = 0;
        let isEven = false;
        
        for (let i = clean.length - 1; i >= 0; i--) {
            let digit = parseInt(clean[i]);
            
            if (isEven) {
                digit *= 2;
                if (digit > 9) digit -= 9;
            }
            
            sum += digit;
            isEven = !isEven;
        }
        
        return sum % 10 === 0;
    }
};

// 实战演示
console.log('邮政编码验证:', ultimateRegexUtils.isZipCode('100000'));
console.log('金额格式化:', ultimateRegexUtils.formatMoney('1234567.89'));
console.log('HTML转义:', ultimateRegexUtils.escapeHtml('<div>Hello & World</div>'));
console.log('信用卡验证:', ultimateRegexUtils.validateCreditCard('4532015112830366'));

看完这些案例,是不是感觉正则表达式也没那么可怕了?关键是要理解每个字符的含义,然后像搭积木一样组合起来。多练几遍,你也能写出让同事刮目相看的正则表达式!

正则表达式虽然看起来复杂,但掌握了这些基本API后,你会发现它就像一把利剑,能够轻松解决各种字符串处理难题。记住,熟能生巧,多练几遍就能运用自如啦!