感谢
本文参考《正则表达式迷你书》
位置匹配
什么是位置
位置就是空字符串。每一个字符不是位置, 正则中的位置可以理解如下
// 空字符串就是位置
"hello" == "" + "h" + "" + "e" + "" + "l" + "" + "l" + "" + "o" + "";
"hello" == "" + "" + "hello"
如何匹配位置
位置 | 含义 |
---|---|
^ | 匹配开头。多行匹配, 匹配行开头 |
$ | 匹配结尾。多行匹配, 匹配行结尾 |
b | 单词边界, 可以是w与W, w与^, w与$之间的位置 |
B | 非单词边界, w与w(字符与字符之间), W与W, ^与W, $与W之间的位置 |
(?=p) | p为一个子模式, (?=p)表示p字符前面的位置, (?=l)表示l字符前面的位置。换一种说法, 位置后面的字符需要是p, 这个位置就是满足正则的位置 |
(?!p) | (?!p)是(?=p)的取反, 所有非(?=p)的位置。例如(?!^)所有非开头前面的位置。 |
^ 和 $
单行匹配
// "#Hello World#"
console.log("Hello World".replace(/^|$/g, '#'))
多行匹配
存在修饰符n, ^$匹配的是每一行的开头和结尾。正则表达式需要添加m全局模式
// "#Hello#
// #World#"
console.log('Hello\nWorld'.replace(/^|$/gm, '#'))
b 和 B
b
b匹配的都是单词边界
// []#I# #L#[] [#ove#] #you# #Fang#[]#Fang#!!!!
"[]I L[] [ove] you Fang[]Fang!!!!".replace(/\b/g, '#')
- ]I 为单词的边界
- L[ 为单词的边界
- [o 为单词的边界
- e] 为单词的边界
- y 为单词的边界
- u 为单词的边界
- F 为单词的边界
- g[ 为单词边界
- ]F 为单词边界
- g 为单词边界
B
B匹配的是所有非单词边界, b的取反
// #[#]I L[#]# #[o#v#e]# y#o#u F#a#n#g!#!#!#!#
"[]I L[] [ove] you F#a#n#g!!!!".replace(/\B/g, '#')
(?=p) 和 (?!p)
p为子模式, p的位置可以是其他的正则表达式
(?=p) 正向先行断言
// 所有空的字符前面添加#
// p前面总共有3个空字符, 所以添加3个#
// '# # # p'
' p'.replace(/(?=[\s])/g, '#')
(?!p) 负向先行断言
(?=p)位置的取反位置
// 所有非空字符的前面
// ' #p#'
' p'.replace(/(?![\s])/g, '#')
案例
不匹配任何字符的正则
// .表示通配符, 但是开头在却在字符的后面, 任何字符都不会满足
var reg = /.^/
千位分割符
可以使用(?=)正向先行断言, 配合d{3}的子模式。(?=(d{3})$), 表示了从结尾开始, 后面有3个数字的位置, 因为不能包含结尾,所以不能是任意三个数字(123, 234这种形式)。
因为我们需要匹配多组这种位置可以使用量词+。(?=(d{3})+$)
"位置" + 123 + "位置" + 456 + $(结尾)
var reg = /(?=(\d{3})+$)/g
// ",123,456,789"
"123456789".replace(reg, ',')
这里我们遇到一个问题, 由于字符串开头(^)也符合正则的要求, 所以会导致这里也会添加一个逗号, 如何去除这个逗号呢?有两种方式。第一种使用B, 因为逗号必须添加在非单词边界中。第二种方式是使用负向先行断言(?!^), 要求了匹配的位置后面不能是开头。
var reg1 = /\B(?=(\d{3})+$)/g
// "123,456,789"
"123456789".replace(reg1, ',')
var reg2 = /(?!^)(?=(\d{3})+$)/g
// "123,456,789"
"123456789".replace(reg2, ',')
? 题外话, 当初我在看书的解答前也思考了这个问题, 我的想法如下
var reg = /[^^](?=(\d{3})+$)/g
// "12,45,789"
"123456789".replace(reg, ',')
结果是"12,45,789", 经过思考我发现自己陷入了一个思维的误区。我们这里需要匹配的是位置而为字符这很重要!
reg的含义是, 后面跟有3个数字并且前面本身不是开头的字符, 而非位置, 从思维上区分位置和字符很重要
? 正则表达式中匹配位置的只有^, $, b, B, (?=p), (?!p)
// ^表示的是位置
"123456789".replace(/^/g, ',')
// [^^]表示的是字符
"1 23456789".replace(/[^^]/g, ',')
如果此时字符串变成了"123456789 123456789", 我们依然需要给字符中添加千位分割符, 我们又该如何做呢?
我们来分析下目前的情况, 这一个字符串中中间有一个space, 我们这时不能继续使用$, 因为如果使用$, space之前的字符将不能匹配, 因为无法满足(d{3})+子模式的条件。
我们可以将$, 替换成b, 表示从单词的边界开始, 前面三个数字之前的那个位置
// ",123,456,789 ,123,456,789"
"123456789 123456789".replace(/(?=(\d{3})+\b)/g, ',')
我们同时不能在单词的边界处添加逗号, 所以可以使用B(非单词边界位置)或者(?!b)(非, 单词边界的前面, 的位置)
// "123,456,789 ,123,456,789"
"123456789 123456789".replace(/\B(?=(\d{3})+\b)/g, ',')
"123456789 123456789".replace(/(?!\b)(?=(\d{3})+\b)/g, ',')
?货币格式化
"1888" ==> "$ 1888.00"
var money = '1888'
var reg1 = /(?=(^))/g
var reg2 = /$/g
money = money.replace(reg1, '$ ')
// "$ 1888.00"
money = money.replace(reg2, '.00')
验证密码
密码的验证规则, 6-12位, 由数字小写字母和大写字母组成, 必须包含两种字符。
首先匹配第一个条件, 6-12位
var reg = /^\w{6, 12}$/g
必须包含数字
// 表示是否存在, 包含数字的字符串, 前面的位置
var reg = /(?=.*[0-9])/g
必须包含小写字母, 必须包含大写字母同理
// 表示是否存在, 包含小写字母的字符串, 前面的位置
var reg = /?=.*[a-z]/g
我们将上面的正则组合
var reg = /((?=.*[0-9])(?=.*[a-z])|(?=.*[0-9])(?=.*[A-Z])|(?=.*[a-z])(?=.*[A-Z]))^\w{6,12}$/
// true
console.log(reg.test('123dde121'))
// true
console.log(reg.test('1231a311'))
// false
console.log(reg.test('12z'))
另一种思路
包含两种类型的字符可以理解为不能全部是数字,不能全部是小写字母和不能全部是大写字母。?!是?=的区反。
// 是否存在, “非”全部是数字的, 前面的位置
var reg1 = /(?![0-9]{6,12})/
// 是否存在, “非”全部是小写字母的, 前面的位置
var reg2 = /(?![a-z]{6,12})/
// 是否存在,“非”全部是大写字母的, 前面的位置
var reg3 = /(?![A-Z]{6,12})/
var reg = /(?![0-9]{6,12})|(?![a-z]{6,12})|(?![A-Z]{6,12})^\w{6,12}$/
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。