image

感谢

本文参考《正则表达式迷你书》

位置匹配

什么是位置

位置就是空字符串。每一个字符不是位置, 正则中的位置可以理解如下


// 空字符串就是位置
"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})+子模式的条件。

image

我们可以将$, 替换成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, ',')

image

?货币格式化

"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'))

image

另一种思路

包含两种类型的字符可以理解为不能全部是数字,不能全部是小写字母和不能全部是大写字母。?!是?=的区反。


// 是否存在, “非”全部是数字的, 前面的位置
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}$/

image


已注销
518 声望187 粉丝

想暴富


下一篇 »
初窥Xterm.js