位置,也称之为 锚,是相邻字符之间的位置;实际上可以理解为一个空字符;如图所示,箭头所指就是位置
那么该如何匹配位置呢?
在 ES5 中,共有 6 个锚:
^, $, \b, \B, (?=p), (?!p)
其可视化表现形式如下图所示:
思维导图:
案例分析:
案例一:不匹配任何东西
/// 写一个正则,不匹配任何东西
let regex = /.^/
console.log( 'test word'.match(regex) )
// => null
案例二:写一个正则,将给定的数字使用千位分隔符表示
/// 写一个正则,将给定的数字使用千位分隔符表示
/// 12345678 => 12,345,678
let string = "12345678"
/// 1, 整出最后一个逗号,即结尾三个数字前面加逗号
let regex = /(?=\d{3}$)/g
console.log( string.replace(regex, ',') )
// => 12345,678
/// 2, 弄出所有的逗号;也就是 \d{3} 匹配的目标字符串至少要出现一次
regex = /(?=(\d{3})+$)/g
console.log( string.replace(regex, ',') )
// => 12,345,678
/// 3, 使用 3 的倍数个数字长度匹配下看看效果
let str = "123456789"
console.log( str.replace(regex, ',') )
// => ,123,456,789
// Ooops! 该死的,开头多了一个逗号,所以需要不能匹配开头位置
/// 4, (?!^) 就可以匹配不是开头的位置
regex = /(?!^)(?=(\d{3})+$)/g
console.log( str.replace(regex, ',') )
// => 123,456,789
// Good! 完美解决!
/// 5, "12345678 123456789" => "12,345,678 123,456,789"
console.log( "12345678 123456789".replace(regex, ',') )
// => 12345678 ,123,456,789
// Ooops! 竟然不行,那么问题在哪呢?因为存在空格,当匹配到空格位置的时候,便终止了
// 有什么办法没呢?
// 开玩笑,必须有啊!位置匹配不是可以有单词边界匹配 \b ,通过这个可以匹配 \w 与 \W 之间的位置 ...
regex = /(?!\b)(?=(\d{3})+\b)/g
console.log( "12345678 123456789".replace(regex, ',') )
// => 12,345,678 123,456,789
// Nice! 与期待的结果一致;那么是否还有可以优化的地方?
// 没错,有的;(?!\b) 这个实际上就是 \b 的取反,这不就是 \B 么?
regex = /\B(?=(\d{3})+\b)/g
console.log( "12345678 123456789".replace(regex, ',') )
// => 12,345,678 123,456,789
/// 应用场景
/// 千分符表示法最常见的应用就是货币格式化
/// 栗子:8888 => ¥ 8888.00
const formatRMB = num => {
return num.toFixed(2).replace(/\B(?=(\d{3})+\b)/g, ',').replace(/^/, '¥ ')
}
console.log( formatRMB(8888) )
// => "¥ 8,888.00"
案例三:密码验证问题
/// 密码验证问题
/// 密码长度 6-12 位,由数字、小写字符、大写字母,以及下划线 _ 组成,但必须包含至少 2 种字符
/// 分析:
/// 1, 密码长度 6-12 位,包含数字、小写字母、大写字母、下划线
let regex = /^[0-9a-zA-Z_]{6,12}$/
/// 2, 必须包含至少 2 种字符;先考虑必须包含数字
regex = /(?=.*[0-9])^[0-9a-zA-Z_]{6,12}$/
console.log( regex.test('_abcdefABC') ) // => false
console.log( regex.test('_abcdefABC12') ) // => true
/// (?=.*[0-9]) ?=.* 匹配到空字符,即位置,空字符后面需要有一个数字 => 必须包含数字
/// 3, 必须包含至少 2 种字符
/// 3.1 同时包含数字和小写字母
regex = /(?=.*[0-9])(?=.*[a-z])^[0-9a-zA-Z_]{6,12}$/
/// 3.1 同时包含数字和大写字母或下划线 (这里将下划线与大写字母放到一起了)
regex = /(?=.*[0-9])(?=.*[A-Z_])^[0-9a-zA-Z_]{6,12}$/
/// 3.2 同时包含小写字母和大写字母
regex = /(?=.*[a-z])(?=.*[A-Z])^[0-9a-zA-Z_]{6,12}$/
/// 综合起来
regex = /((?=.*[0-9])(?=.*[a-z])|(?=.*[0-9])(?=.*[A-Z_])|(?=.*[a-z])(?=.*[A-Z_]))^[0-9a-zA-Z_]{6,12}$/
console.log( regex.test('12345678') ) // => false
console.log( regex.test('abcdefg') ) // => false
console.log( regex.test('ABCDEFG') ) // => false
console.log( regex.test('ab12345') ) // => true
console.log( regex.test('AB1234HI') ) // => true
console.log( regex.test('ABC_EFG') ) // => false
console.log( regex.test('abc_edf') ) // => true
console.log( regex.test('abcdEFG12') ) // => true
console.log("===============================================")
/// 另一种思路:
/// 至少包含两种字符 => 不能全部都是数字,也不能全是小写字母,也不能全是大写字母或下划线
/// 先看不能全是数字该怎么办?
/// (?!^[0-9]{6,12}$) 如此便可,意思就是匹配位置后面不能是数字
regex = /(?!^[0-9]{6,12}$)(?!^[a-z]{6,12}$)(?!^[A-Z_]{6,12}$)^[0-9a-zA-Z_]{6,12}$/
console.log( regex.test('12345678') ) // => false
console.log( regex.test('abcdefg') ) // => false
console.log( regex.test('ABCDEFG') ) // => false
console.log( regex.test('ab12345') ) // => true
console.log( regex.test('AB1234HI') ) // => true
console.log( regex.test('ABC_EFG') ) // => false
console.log( regex.test('abc_edf') ) // => true
console.log( regex.test('abcdEFG12') ) // => true