正则表达式 - 常用模式
正则表达式是处理字符串的强大工具,用于匹配、查找、替换和验证文本模式。
基础验证
手机号码
typescript
// 中国大陆手机号(11位,1开头)
const phoneRegex = /^1[3-9]\d{9}$/
// 使用示例
phoneRegex.test('13812345678') // true
phoneRegex.test('12345678901') // false
// 宽松版本(支持+86和空格)
const phoneLooseRegex = /^(\+?86)?[\s-]?1[3-9]\d{9}$/
phoneLooseRegex.test('+86 138 1234 5678') // true
phoneLooseRegex.test('86-13812345678') // true邮箱地址
typescript
// 标准邮箱格式
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
// 使用示例
emailRegex.test('user@example.com') // true
emailRegex.test('user.name@domain.co.uk') // true
emailRegex.test('invalid@') // false
// 更严格的邮箱验证
const strictEmailRegex = /^[a-zA-Z0-9]([a-zA-Z0-9._-]*[a-zA-Z0-9])?@[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z]{2,})+$/身份证号码
typescript
// 18位身份证号(含校验位)
const idCardRegex = /^[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/
// 使用示例
idCardRegex.test('110101199001011234') // true
idCardRegex.test('11010119900101123X') // true
// 15位或18位身份证号
const idCardBothRegex = /^[1-9]\d{5}(19|20)?\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]?$/密码强度
typescript
// 至少8位,包含大小写字母和数字
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/
// 至少8位,包含大小写字母、数字和特殊字符
const strongPasswordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/
// 使用示例
passwordRegex.test('Abc12345') // true
passwordRegex.test('abc12345') // false (缺少大写)
strongPasswordRegex.test('Abc@12345') // true用户名
typescript
// 4-16位,字母、数字、下划线
const usernameRegex = /^[a-zA-Z0-9_]{4,16}$/
// 使用示例
usernameRegex.test('user_123') // true
usernameRegex.test('abc') // false (太短)
usernameRegex.test('user@123') // false (包含非法字符)数字验证
整数
typescript
// 正整数
const positiveIntRegex = /^[1-9]\d*$/
// 非负整数(包含0)
const nonNegativeIntRegex = /^\d+$/
// 负整数
const negativeIntRegex = /^-[1-9]\d*$/
// 整数(正负整数和0)
const integerRegex = /^-?[0-9]\d*$/
// 使用示例
positiveIntRegex.test('123') // true
positiveIntRegex.test('0') // false
nonNegativeIntRegex.test('0') // true
negativeIntRegex.test('-123') // true小数
typescript
// 正小数
const positiveDecimalRegex = /^[0-9]+\.[0-9]+$/
// 保留2位小数
const twoDecimalRegex = /^[0-9]+(\.[0-9]{1,2})?$/
// 金额格式(最多2位小数)
const moneyRegex = /^(0|[1-9]\d*)(\.\d{1,2})?$/
// 使用示例
positiveDecimalRegex.test('3.14') // true
twoDecimalRegex.test('99.99') // true
twoDecimalRegex.test('99.999') // false
moneyRegex.test('1234.56') // true百分比
typescript
// 0-100的百分比
const percentRegex = /^(100(\.0{1,2})?|[1-9]?\d(\.\d{1,2})?)$/
// 使用示例
percentRegex.test('99.99') // true
percentRegex.test('100') // true
percentRegex.test('100.5') // falseURL 和网络
URL 地址
typescript
// HTTP/HTTPS URL
const urlRegex = /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&/=]*)$/
// 使用示例
urlRegex.test('https://www.example.com') // true
urlRegex.test('http://example.com/path?query=1') // true
// 更宽松的URL验证
const looseUrlRegex = /^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/IP 地址
typescript
// IPv4 地址
const ipv4Regex = /^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$/
// 使用示例
ipv4Regex.test('192.168.1.1') // true
ipv4Regex.test('255.255.255.255') // true
ipv4Regex.test('256.1.1.1') // false
// IPv6 地址(简化版)
const ipv6Regex = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/域名
typescript
// 域名
const domainRegex = /^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/
// 使用示例
domainRegex.test('example.com') // true
domainRegex.test('sub.example.com') // true
domainRegex.test('example') // false端口号
typescript
// 端口号(1-65535)
const portRegex = /^([1-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$/
// 使用示例
portRegex.test('80') // true
portRegex.test('8080') // true
portRegex.test('65536') // false日期和时间
日期格式
typescript
// YYYY-MM-DD 格式
const dateRegex = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/
// 使用示例
dateRegex.test('2024-11-28') // true
dateRegex.test('2024-13-01') // false
dateRegex.test('2024-11-32') // false
// YYYY/MM/DD 格式
const dateSlashRegex = /^\d{4}\/(0[1-9]|1[0-2])\/(0[1-9]|[12]\d|3[01])$/
// DD-MM-YYYY 格式
const dateDDMMYYYYRegex = /^(0[1-9]|[12]\d|3[01])-(0[1-9]|1[0-2])-\d{4}$/时间格式
typescript
// 24小时制 HH:mm:ss
const time24Regex = /^([01]\d|2[0-3]):([0-5]\d):([0-5]\d)$/
// 使用示例
time24Regex.test('23:59:59') // true
time24Regex.test('24:00:00') // false
// 24小时制 HH:mm
const time24ShortRegex = /^([01]\d|2[0-3]):([0-5]\d)$/
// 12小时制 hh:mm AM/PM
const time12Regex = /^(0?[1-9]|1[0-2]):([0-5]\d)\s?(AM|PM|am|pm)$/
time12Regex.test('12:30 PM') // true日期时间
typescript
// YYYY-MM-DD HH:mm:ss
const datetimeRegex = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])\s([01]\d|2[0-3]):([0-5]\d):([0-5]\d)$/
// 使用示例
datetimeRegex.test('2024-11-28 15:30:45') // true
// ISO 8601 格式
const iso8601Regex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?$/
iso8601Regex.test('2024-11-28T15:30:45.123Z') // true中文相关
中文字符
typescript
// 纯中文
const chineseRegex = /^[\u4e00-\u9fa5]+$/
// 使用示例
chineseRegex.test('你好世界') // true
chineseRegex.test('Hello世界') // false
// 中文、字母、数字
const chineseAlphanumRegex = /^[\u4e00-\u9fa5a-zA-Z0-9]+$/
// 中文姓名(2-4个字)
const chineseNameRegex = /^[\u4e00-\u9fa5]{2,4}$/
chineseNameRegex.test('张三') // true
chineseNameRegex.test('欧阳修') // true车牌号
typescript
// 新能源车牌
const newEnergyPlateRegex = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-DF-HJ-NP-Z0-9]{5}[A-DF-HJ-NP-Z0-9挂学警港澳]$/
// 普通车牌
const plateRegex = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]$/
// 使用示例
plateRegex.test('京A12345') // true
plateRegex.test('沪B88888') // true邮政编码
typescript
// 中国邮政编码(6位数字)
const postalCodeRegex = /^[1-9]\d{5}$/
// 使用示例
postalCodeRegex.test('100000') // true
postalCodeRegex.test('000000') // false文件和路径
文件名
typescript
// 文件名(不含路径)
const filenameRegex = /^[^\\/:*?"<>|]+$/
// 使用示例
filenameRegex.test('document.pdf') // true
filenameRegex.test('file:name.txt') // false
// 特定扩展名
const imageFileRegex = /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i
imageFileRegex.test('photo.jpg') // true
imageFileRegex.test('image.PNG') // true (不区分大小写)文件路径
typescript
// Windows 路径
const windowsPathRegex = /^[a-zA-Z]:\\(?:[^\\/:*?"<>|\r\n]+\\)*[^\\/:*?"<>|\r\n]*$/
// Unix/Linux 路径
const unixPathRegex = /^\/(?:[^/\0]+\/)*[^/\0]*$/
// 使用示例
windowsPathRegex.test('C:\\Users\\Documents\\file.txt') // true
unixPathRegex.test('/home/user/documents/file.txt') // true银行卡和支付
银行卡号
typescript
// 银行卡号(16-19位)
const bankCardRegex = /^[1-9]\d{15,18}$/
// 使用示例
bankCardRegex.test('6222021234567890123') // true
// 带空格的银行卡号
const bankCardWithSpaceRegex = /^[1-9]\d{3}\s?\d{4}\s?\d{4}\s?\d{4}(\s?\d{3})?$/
bankCardWithSpaceRegex.test('6222 0212 3456 7890') // true信用卡
typescript
// Visa 卡
const visaRegex = /^4[0-9]{12}(?:[0-9]{3})?$/
// MasterCard
const masterCardRegex = /^5[1-5][0-9]{14}$/
// 银联卡
const unionPayRegex = /^62[0-9]{14,17}$/颜色值
十六进制颜色
typescript
// HEX 颜色(#RGB 或 #RRGGBB)
const hexColorRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/
// 使用示例
hexColorRegex.test('#fff') // true
hexColorRegex.test('#ffffff') // true
hexColorRegex.test('#FF5733') // true
hexColorRegex.test('#gggggg') // falseRGB/RGBA 颜色
typescript
// RGB 格式
const rgbRegex = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/
// RGBA 格式
const rgbaRegex = /^rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0?\.\d+|1(\.0)?)\s*\)$/
// 使用示例
rgbRegex.test('rgb(255, 255, 255)') // true
rgbaRegex.test('rgba(255, 0, 0, 0.5)') // true版本号
typescript
// 语义化版本号(Semantic Versioning)
const semverRegex = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/
// 使用示例
semverRegex.test('1.0.0') // true
semverRegex.test('1.2.3-alpha.1') // true
semverRegex.test('2.0.0+build.123') // true
// 简单版本号
const simpleVersionRegex = /^\d+\.\d+\.\d+$/
simpleVersionRegex.test('1.0.0') // true实用工具函数
验证函数封装
typescript
// 验证工具类
class Validator {
// 手机号
static isPhone(value: string): boolean {
return /^1[3-9]\d{9}$/.test(value)
}
// 邮箱
static isEmail(value: string): boolean {
return /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(value)
}
// 身份证
static isIdCard(value: string): boolean {
return /^[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/.test(value)
}
// URL
static isUrl(value: string): boolean {
return /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&/=]*)$/.test(value)
}
// 纯中文
static isChinese(value: string): boolean {
return /^[\u4e00-\u9fa5]+$/.test(value)
}
}
// 使用示例
Validator.isPhone('13812345678') // true
Validator.isEmail('user@example.com') // true提取信息
typescript
// 提取所有邮箱地址
function extractEmails(text: string): string[] {
const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g
return text.match(emailRegex) || []
}
// 提取所有URL
function extractUrls(text: string): string[] {
const urlRegex = /https?:\/\/[^\s]+/g
return text.match(urlRegex) || []
}
// 提取所有手机号
function extractPhones(text: string): string[] {
const phoneRegex = /1[3-9]\d{9}/g
return text.match(phoneRegex) || []
}
// 使用示例
const text = '联系我:13812345678 或 user@example.com,网站:https://example.com'
extractPhones(text) // ['13812345678']
extractEmails(text) // ['user@example.com']
extractUrls(text) // ['https://example.com']格式化处理
typescript
// 格式化手机号(添加空格)
function formatPhone(phone: string): string {
return phone.replace(/(\d{3})(\d{4})(\d{4})/, '$1 $2 $3')
}
// 格式化银行卡号(每4位一个空格)
function formatBankCard(card: string): string {
return card.replace(/(\d{4})(?=\d)/g, '$1 ')
}
// 隐藏手机号中间4位
function maskPhone(phone: string): string {
return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')
}
// 隐藏邮箱用户名
function maskEmail(email: string): string {
return email.replace(/(.{2}).*(@.*)/, '$1***$2')
}
// 使用示例
formatPhone('13812345678') // '138 1234 5678'
formatBankCard('6222021234567890') // '6222 0212 3456 7890'
maskPhone('13812345678') // '138****5678'
maskEmail('username@example.com') // 'us***@example.com'在线测试工具
推荐使用以下在线工具测试正则表达式:
最佳实践
- 性能优化: 避免使用过于复杂的正则,考虑性能影响
- 可读性: 使用注释说明正则的用途,复杂的正则可以拆分
- 边界情况: 充分测试边界值和异常输入
- 安全性: 避免正则表达式拒绝服务攻击(ReDoS)
- 国际化: 考虑不同地区的格式差异
注意事项
- ⚠️ 正则表达式只能做格式验证,不能保证数据的真实性
- ⚠️ 某些复杂验证(如邮箱)建议结合后端验证
- ⚠️ 注意正则表达式的性能,避免回溯过多
- ⚠️ 不同语言的正则引擎可能有差异