Jin's Blog
HOME WEEKLY ARCHIVE ABOUT RSS

JS 正则表达式

因为自己的正则学的真的不是很好,所以重新学习一边,顺便记录一下,以备复习。

正则工具

推荐这款正则的工具,Github:Regexper,用图片解释的正则,很方便很实用。因为是国外的网站,有时候会上不去,所以推荐下载下来本地运行,这样会比较方便。

初始化

使用构造函数的时候需要注意 \ 反斜杠是需要转义的。

修饰符

let reg = /\d/gim
reg.global
//true

reg.global = false
reg.global
// true

修饰符默认都是 false,而且都是只读的,只能在创建的时候确认,创建之后是无法修改的。

字符类

**[]**:[abc] 代表 a、b、c 中的一个匹配就可以。

字符类取反向

^:取反向类。

范围类

[a-z]:从 a 到 z 的任意字符,这是个闭区间,然后 [a-zA-Z] 可以连写。

预定义类

边界

量词

贪婪模式

正则表达式会匹配尽量多的值,直到匹配失败。例如:

'12345678'.replace(/\d{3,6}/, 'M')
// "M78"

非贪婪模式

如果要取消贪婪模式,只需要在量词后面加一个问号 /\d{4,6}?/。例如:

'12345678'.replace(/\d{3,6}?/, 'M')
// "M45678"

分组

使用 () 可以达到分组功能
abcd{4} ----> (abcd){4}

分组捕获

'2011-01-12'.replace(/(\d{4})-(\d{2})-(\d{2})/, '$2--$3--$1')
// '01--12--2011'

忽略分组

不希望捕获某些分组,只需要在分组内加上 ? : ,就可以了。

'2011-01-12'.replace(/(?:\d{4})-(\d{2})-(\d{2})/, '$2--$3--$1')
// '12--$3--01'

可以用 | 达到效果,Byron | Casper,使用分组来不干涉其他表达式。
BBry(on|CA)sper

前瞻

正则表达式从文本头部向尾部开始解析,所以文本的尾部方向,称之为“前”(这个理解起来有点难,我想了好久)。所谓前瞻就是正则在匹配到规则的时候,向前检查是否符合断言。(其实还有后顾,但是 JS 暂时好像没有支持)。

正向前瞻 exp(?=assert)

正向前瞻指的就是,表达式匹配以后还需要向前检查是否符合(正向)断言(assert)。例子:

'a2*34v8'.replace(/\w(?=\d)/g, 'X')
// 'X2*X4X8'

反向前瞻 exp(?!assert)

反向前瞻指的就是,表达式匹配以后还需要向前检查是否不符合(反向)断言(assert)。例子:

'a2*34v8'.replace(/\w(?!\d)/g, 'X')
// 'aX*3XvX'

对象属性

RegExp.prototype.test(str)

用于测试字符串参数中是否存在匹配正则表达式模式的字符串,存在返回 true,否则返回 false。

非全局 (没g)
当不使用全局的时候,test() 方法会直接返回 true,或者 false。

全局 (有g)
这个时候就会被 lastIndex(当前匹配结果的,最后一个字符的,下一个字符) 影响了,因为每次匹配之后,它的 lastIndex 都会改变,这时候就会影响到 test() 方法的结果。看例子:

let reg = /\w/g
while(reg.test('ab')) {
console.log(reg2.lastIndex)
}
// 1
// 2

当但三次循环的时候,因为 lastIndex 为 2 所以就直接返回了 false,循环结束。

RegExp.prototype.exec(str)

使用正则对字符串执行搜索,并将更新全局 RegExp 对象的属性以反映匹配结果。

非全局 (没g)

全局(有g)

直接看例子吧:

let ts = 'a1b2c3d4e5'
let reg = /\d(\w)(\d)/g
let ret
while (ret = reg.exec(ts)) {
console.log(ret)
}

// ["1b2", "b", "2", index: 1, input: "a1b2c3d4e5", groups: undefined]
// ["3d4", "d", "4", index: 5, input: "a1b2c3d4e5", groups: undefined]

String.prototype.search(reg)

String.prototype.match(reg)

非全局 (没g)

全局(有g)

'a1a2b3c4d5e'.match(/\d(\w)\d/g)
// ["1a2", "3c4"]

String.prototype.split(reg)

一般的使用:'a,b,c,d'.split(','); ---> ["a", "b", "c", "d"]'

使用正则

'a1a2b3c4d5e'.split(/\d/)
// ["a", "a", "b", "c", "d", "e"]

String.prototype.replace(reg)

replace 的第二个值可以传入 function 来处理复杂的替换。

function参数含义:function 会在每次匹配替换的时候调用,有四个参数。返回值就是替换的内容。

  1. 匹配字符串
  2. 正则表达式分组内容,没有分组则没有该参数
  3. 匹配项在字符串中的 index
  4. 原字符串

例子:

// 例子1:没有分组
'a1a2b3c4d5e'.replace(/\d/g, (match, index, o) => {
return parseInt(match) + 5
})
// "a6a7b8c9d10e"

// 例子2:有分组
'a1a2b3c4d5e'.replace(/(\d)\w(\d)/g, (match, g1, g2, index, o) => {
return g1 + g2
})
// "a12b34d5e"

练习

使用正则来实现一个时间的函数。

// 传入一个实例化后的时间,以及需要的时间格式,如 yyyy-mm-dd
// new Date(),会返回一个Date对象的实例。如果不加参数,实例代表的就是当前时间。
function formaDate (date, fmt) {
// 找到 y 字符,然后替换成年
if (/(y+)/i.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
}
let o = {
'M+': date.getMonth() + 1,
'd+': date.getDate(),
'h+': date.getHours(),
'm+': date.getMinutes(),
's+': date.getSeconds()
}
for (let k in o) {
// 找到相应字符,然后进行替换
if (new RegExp(`(${k})`, 'i').test(fmt)) {
let str = o[k] + ''
fmt = fmt.replace(RegExp.$1, (m) => {
// 是否需要补全0,例如 8:5 --> 08:05
// 如果需要,则使用 substr 方法操作
if (m.length === 2) {
str = ('00' + str).substr(str.length)
}
return str
})
}
}
return fmt
}

// 然后我们只需要传入实例化的时间,以及时间的格式,就可以返回符合格式的时间,非常的方便
formaDate(new Date(), 'yyyy-mm-dd hh:mm')
// "2018-04-15 20:02"
formaDate(new Date(), 'mm-dd-yyyy')
// "04-15-2018"
PREVIOUS

JS 中的 autoprefixer

NEXT

关于 JavaScript 中的复制数组

ALL TAGS