「JavaScript 正则表达式迷你书.pdf」https://www.aliyundrive.com/s/i77Fq6HocdT
匹配 16 进制颜色
匹配 6 位的 16 进制
const regex = /#[0-9a-fA-F]{6}/
颜色也有可能是 3 位的,由于管道符也是贪婪匹配,所以需要先匹配 6 位再匹配 3 位
const regex = /#[0-9a-fA-F]{6}|[0-9a-fA-F]{3}/
匹配时间
匹配小时,00-19,20-23
const regex = /([01][0-9]|2[0-3])/
匹配分钟,00-59
const regex = /[0-5][0-9]/
最终结果
const regex = /^([01][0-9]|2[0-3]):[0-5][0-9]$/
匹配日期
匹配年份,0000-xxxx
const regex = /\d{4}/
匹配月份,01-12
const regex = /(0[1-9]|1[0-2])/
匹配日,01-31
const regex = /0[0-9]|[12][0-9]|3[01]/
最终结果
const regex = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/
匹配文件路径
匹配磁盘
const regex = /[a-zA-Z]:\\/
匹配文件夹
const regex = /[^\\:*<>|"?\r\n/]+\\/
完整路径
const regex = /^[a-zA-Z]:\\([^\\:*<>|"?\r\n/]+\\)*([^\\:*<>|"?\r\n/]+?$)/
位置:
^
: 开头$
: 结尾\b
: 单词边界,\w
与\W
之间的位置(\w
===[0-9a-zA-Z_]
数字字母下划线)\B
: 非单词的边界,(?=p)
: 以 p 结尾(?!p)
: 不以 p 结尾
数字千分位分隔符
添加最后一位的逗号
"123456789".replace(/?=\d{3}$/g, ",") // => "123456,789"
添加所有逗号
"123456789".replace(/(?=(\d{3})+$)/g, ",") // => ",123,456,789"
去除开头的逗号
"123456789".replace(/(?!^)(?=(\d{3})+$)/g, ",") // => "123,456,789"
多组数字格式化
"123456789 123456789".replace(/(?!\b)(?=(\d{3})+\b)/g, ",") // 等价于 => "123456789 123456789".replace(/\B(?=(\d{3})+\b)/g, ",") // => "123,456,789 123,456,789"
验证密码
必须包含数字
const regex = /(?=.*[0-9])/
必须包含汉字
const regex = /(?=.*[\u4e00-\u9fa5])/
必须包含数字和字母
const regex = /(?=.*[0-9])(?=.*[a-zA-Z])/
必须包含数字和汉字
const regex = /(?=.*[0-9])(?=.*[\u4e00-\u9fa5])/
必须包含字母和汉字
const regex = /(?=.*[a-zA-Z])(?=.*[\u4e00-\u9fa5])/
必须包含数字、字母和汉字,且至少包含两种字符,两两组合,那么组合数就是
,三种情况 const regex = /(?=.*[0-9])(?=.*[a-zA-Z])|(?=.*[0-9])(?=.*[\u4e00-\u9fa5])|(?=.*[a-zA-Z])(?=.*[\u4e00-\u9fa5])/
再加一个位数限制:最低 6 位,最高 20 位
const regex = /((?=.*[0-9])(?=.*[a-zA-Z])|(?=.*[0-9])(?=.*[\u4e00-\u9fa5])|(?=.*[a-zA-Z])(?=.*[\u4e00-\u9fa5]))^[0-9a-zA-Z\u4e00-\u9fa5]{6,20}/
如果再加两种字符:下划线(
_
)、短杠(-
),要是采用和上面相同的方式:两两组合,== 10,意味着要写 10 种情况,工程量可想而知。换个角度,至少包含两种字符的对立事件就是:不能全都是数字、字母和汉字 不能全为数字
const regex = /(?!^[0-9]+$)/
不能全都是数字、字母和汉字
const regex = /(?!^[0-9]+$)(?!^[a-zA-Z]+$)(?!^[\u4e00-\u9fa5]+$)/
最终版
const regex = /(?!^[0-9]{6,20}$)(?!^[a-zA-Z]{6,20}$)(?!^[\u4e00-\u9fa5]{6,20}$)(?!^-{6,20}$)(?!^_{6,20}$)^[0-9a-zA-Z\u4e00-\u9fa5\-_]{6,20}/
格式化日期(分组引用)
yyyy-mm-dd
格式化成mm/dd/yyyy
const regex = /(\d{4})-(\d{2})-(\d{2})/ const date = "2022-08-10" const result = date.replace(regex, "$2/$3/$1") // => "08/10/2022" // 等价于 => const result = date.replace(regex, function () { return `${RegExp.$2}/${RegExp.$3}/${RegExp.$1}` }) // 等价于 => const result = date.replace(regex, function (match, year, month, day) { return `${month}/${day}/${year}` })
匹配多种日期格式(反向引用)
要匹配:
yyyy.mm.dd
、yyyy-mm-dd
和yyyy/mm/dd
const regex = /\d{4}(\.|-|\/)\d{2}\1\d{2}/
\10
表示第10
个分组,若想匹配\1
和0
,请使用(?:\1)0
或者\1(?:0)
((?:p)
表示非捕获括号,不会对括号中的内容进行分组);- 若分组
\5
不存在,则匹配"\5"
,相当于对"5"
进行了转义;- 若分组后带有量词,则匹配最后一次捕获的结果。
模拟字符串 trim
方法
匹配开头结尾的空白符,然后替换为空(效率更高)
function trim(str) { return str.replace(/^\s+|\s+$/g, "") }
匹配整个字符串,然后用引用的部分替换整体
function trim(str) { return str.replace(/^\s*(.*?)\s*$/, "$1") }
单词首字母大写
function firstUppercase(str) {
return str.toLowerCase().replace(/(?:^|\s)\w/g, c => c.toUpperCase())
}
// => 如果添加修饰符 `g`,则是将所有单词首字母大写
// => 如果不加修饰符 `g`,则只会将第一个单词的首字母大写
驼峰化
function camelize(str) {
return str.replace(/[-_\s]+(.)?/g, (match, c) => {
return c ? c.toUpperCase() : ""
})
}
短杠化
function kebablize(str) {
return str
.replace(/([A-Z])/g, "-$1")
.replace(/[-_\s]+/g, "-")
.toLowerCase()
}
匹配成对标签
匹配开标签
const regex = /<[^>]+>/
匹配闭标签
const regex = /<\/[^>]+>/
完整正则
const regex = /<([^>]+)>[\s\S]*<\/\1>/
需要转义的元字符
^
、$
、.
、*
、+
、?
、|
、\
、/
、(
、)
、[
、]
、{
、}
、=
、!
、:
、-
、,
,这些字符串匹配时要加 \
匹配 IPV4 地址
const regex = /^((0{0,2}\d|0?\d{2}|1\d{2}|2[0-4]\d|25[0-5])\.){3}(0{0,2}\d|0?\d{2}|1\d{2}|2[0-4]\d|25[0-5])$/
匹配固定电话
要匹配:055188888888
、0551-88888888
和 (0551)88888888
,前四位为区号,后八位为号码
第一种的匹配规则
const regex = /0\d{3}[1-9]{8}/
第二种的匹配规则
const regex = /0\d{3}-[1-9]{8}/
第三种的匹配规则
const regex = /\(0\d{3}\)[1-9]{8}/
结合第一种和第二种
const regex = /0\d{3}-?[1-9]{8}/
三种结合的最终匹配规则
const regex = /(0\d{3}-?|\(0\d{3}\))[1-9]{8}/
匹配浮点数
要匹配:
情况一:
1.22
、+1.22
、-1.22
情况二:
10
、+10
、-10
情况三:
.2
、+.2
、-.2
情况一:
const regex = /^[+-]?\d+\.\d*$/
情况二:
const regex = /^[+-]?\d+$/
情况三:
const regex = /^[+-]?\.\d+$/
最终结果
const regex = /^[+-]?(\d+\.\d*|\d+|\.\d+)$/
提升效率
使用具体型字符组来代替通配符,消除回溯
匹配
123"456"789
中的"456"
- /".*"/ + /"[^"]*/
使用非捕获分组
捕获分组,意味着需要额外的内存来保存分组的结果,对于不需要分组引用或反向引用的采用非捕获分组
- /^\d+("[^"]*")\d+$/ + /^\d+(?:"[^"]*")\d+$/
独立出确定字符:可以减少回溯,加快匹配速度
- /a+/ + /aa*/
提取分支公共部分
- /^abc|^def/ + /^(?:abc|def)/ - /this|that/ + /th(?:is|at)/
减少分支数量,缩小它们的范围,不过降低了可读性
- /red|read/ + /rea?d/
replace
的应用
当第二个参数是字符串时,以下字符有特殊含义
属性 描述 $1,$2,···,$99 匹配第 1-99
个分组里捕获的文本$& 匹配到的字符文本 $` 匹配到的字符左边文本 $’ 匹配到的字符右边文本 $$ 美元符号 当第二个参数是函数时,函数里的回调参数与使用
match(非全局匹配)
匹配到的结果类似"123abc456".match(/(\d+)[^\d]*(\d+)/) // => ['123abc456', '123', '456', index: 0, input: '123abc456', groups: undefined] // 第一个参数:匹配到的结果 // 第二个参数:分组一的结果 // 第三个参数:分组二的结果 // 若还有多个分组,则列完分组结果... // 倒数第三个参数:匹配的开始索引 // 倒数第二个参数:原字符串 // 倒数第一个参数:没有修饰符 g,所以为 undefined
"123abc456".replace(/(\d+)[^\d]*(\d+)/, function (match, $1, $2, index, input) { console.log([match, $1, $2, index, input]) // => ['123abc456', '123', '456', 0, '123abc456'] })
获取当前日期(yyyy-MM-dd HH:mm:ss)
function getCurrentDate() {
return new Date()
.toLocaleString()
.replace(/\/(\d)(?=(\/|\s))/g, "-0$1")
.replace(/\//g, "-")
}
模拟 getElementByClassName
function getElementByClassName(className) {
const elements = document.getElementByTagName("*")
const regex = new RegExp(`(^|\\s)${className}(\\s|$)`)
const result = []
for (let i = 0; i < element.length; i++) {
const element = elements[i]
if (regex.test(element.className)) {
result.push(element)
}
}
return result
}
封装一个类型检验工具函数
const utils = {}
"Boolean|String|Number|Function|Array|Date|RegExp|Object|Error".split("|").forEach(item => {
utils[`is${item}`] = obj => {}.toString.call(obj) === `[object ${item}]`;
})
console.log(utils.isArray([1,2])); // true
console.log(utils.isArray({})); // false
压缩字符串
function compress(str) {
const keys = {}
str.replace(/([^=&]+)=([^&]*)/g, function (full, key, value) {
keys[key] = (keys[key] ? `${keys[key]},` : "") + value
})
const result = []
for (const key in keys) {
result.push(`${key}=${keys[key]}`)
}
return result.join("&")
}
console.log(compress("a=1&b=2&a=3&b=4"))
// => "a=1,3&b=2,4"