看懂火星文(三) 2019.4.3更新 🎉

《看懂火星文(三) 2019.4.3更新 🎉》

谢谢

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

分组和分支组织

分组

括号能够供应分组的功用。/a+/, 标示a涌现屡次。/(ab)+/, 则是将ab作为一组,示意ab涌现屡次。

分组援用

运用括号能够完成数据提取和替代操纵。我们以婚配日期(yyyy-mm-dd)为例


// 无括号版本
var reg1 = /\d{4}-\d{2}-\d{2}/

《看懂火星文(三) 2019.4.3更新 🎉》


// 有括号版本
var reg2 = /(\d{4})-(\d{2})-(\d{2})/

《看懂火星文(三) 2019.4.3更新 🎉》

正则引擎在婚配的历程当中,会存储每一个分组婚配到的数据

提取分组数据

match要领

match接收一个正则表达式作为参数。假如正则表达式中有g标示, 将返回与完整正则表达式婚配的一切效果,但不会返回捕捉组。假如没有运用g标示,则仅返回第一个完整婚配及其相干的捕捉组。

var regex = /(\d{4})-(\d{2})-(\d{2})/g
var string = "2017-06-12 2017-06-12"

// ["2017-06-12", "2017-06-12"]
// 返回与完整正则表达式婚配的一切效果, 不含分组的效果
string.match(regex)

var regex = /(\d{4})-(\d{2})-(\d{2})/
var string = "2017-06-12 2017-06-12"

// 只返回第一个完整婚配和其分组
// ["2017-06-12", "2017", "06", "12", index: 0, input: "2017-06-12 2017-06-12", groups: undefined]
string.match(regex)

exec要领

exec要领接收一个字符串作为参数。假如exec婚配失利将会返回null, 假如婚配胜利exec要领将会返回一个数组。

返回的数组将完整婚配胜利的文本作为第一项,而分组婚配的效果在数组位置0的背面。返回的效果同时具有index属性, 标示了婚配字符为于原始字符的索引。input属性则是原始的字符串。

注重当正则对象是不是包括g返回效果是不一样的。假如正则中含有g标示, 那末正则对象的lastIndex(下一次婚配最先的位置), 会更新。而假如不含有g, 正则的lastIndex不会更新。


var regex = /(\d{4})-(\d{2})-(\d{2})/
var string = "2017-06-12 2017-06-12"

// ["2017-06-12", "2017", "06", "12", index: 0, input: "2017-06-12 2017-06-12", groups: undefined]
// regex.lastIndex === 0
regex.exec(string)
// ["2017-06-12", "2017", "06", "12", index: 0, input: "2017-06-12 2017-06-12", groups: undefined]
// regex.lastIndex === 0
regex.exec(string)

var regex = /(\d{4})-(\d{2})-(\d{2})/g
var string = "2017-06-12 2017-06-12"

// ["2017-06-12", "2017", "06", "12", index: 0, input: "2017-06-12 2017-06-12", groups: undefined]
regex.exec(string)
// ["2017-06-12", "2017", "06", "12", index: 11, input: "2017-06-12 2017-06-12", groups: undefined]
// regex.lastIndex === 21
regex.exec(string)

RegEx

我们也能够经由历程RegEx全局的组织函数来猎取分组婚配的效果。组织函数的全局属性$1到$9存储了分组婚配的效果。


var regex = /(\d{4})-(\d{2})-(\d{2})/g
var string = "2017-06-12 2017-06-12"

// 任何正则操纵即可
regex.exec(string)

// "2017"
RegExp.$1

替代分组数据

我们能够经由历程replace要领合营分组婚配的效果, 完成替代分组数据

replace

str.replace(regexp|substr, newSubStr|func)

  • regexp 一个正则表达式对象,该正则所婚配的内容会被replace的第二个参数(或许函数的返回值)替代掉
  • substr 当str中含有substr, 会被第二个参数替代, 唯一第一个婚配项会被替代
  • newSubStr 用于替代掉第一个参数在原字符串中的婚配部份的字符串。该字符串中能够内插一些特别的变量名(见下表)
  • func 函数的返回值将替代掉第一个参数婚配到的效果
变量名寄义
$1, $2, $3……第n个分组婚配的效果
$`插进去当前婚配的子串左侧的内容
$’插进去当前婚配的子串右侧的内容
$&当前婚配的子串

// "🍰loHel🍕"
'🍰Hello🍕'.replace(/(Hel)(lo)/, '$2$1')

// "🍰ello🍕ello🍕"
// H被替代为ello🍕
'🍰Hello🍕'.replace(/H/, "$'")

// "🍰🍰ello🍕"
// H被替代为🍰
'🍰Hello🍕'.replace(/H/, "$`")
指定一个函数作为参数

函数的返回值作为替代字符串。 (注重:上面提到的特别替代参数在这里不能被运用。) 别的要注重的是,假如第一个参数是正则表达式,而且其为全局婚配情势,那末这个要领将被屡次挪用,每次婚配都会被挪用。


// 函数每婚配到一次, 就会被挪用
'🍰🍕🍔🍕🥪'.replace('/🍕/g', function () {
  return '🍬'
})
函数的参数寄义
match当前婚配的子串
p1, p2, …… pn婚配的分组数据

示例

将’2019-01-01’替代为01/01/2019

var str = '2019-01-01'

var reg = /(\d{4})-(\d{2})-(\d{2})/

// 01/01/2019
var result = str.replace(reg, '$2/$3/$1')

// 01/01/2019
result = str.replace(reg, function (match, year, month, day) {
  return `${month}/${day}/${year}`
})

反向援用

我们如今有一个需求, 运用一个正则表达式婚配以下花样的📅日期字符串

2019-01-01, 2019.01.01, 2019/01/01, 而且前后的支解标记须要保持一致


var reg = /\d{4}(\/|\.|-)\d{2}(\/|\.|-)\d{2}/

👆 上面的正则达到了最基本的目标, 然则我们还没有处理前后支解符须要保持一致的题目。

这时刻我们能够到反向援用, 1示意第一个分组所婚配到的详细的字符, 2, 3同理

《看懂火星文(三) 2019.4.3更新 🎉》


var reg = /\d{4}(-|\/|\.)\d{2}\1\d{2}/

括号嵌套

var regex = /^((\d)(\d(\d)))\1\2\3\4$/
var string = "1231231233"

// 分组一
// \d\d\d \1对应 123
// 分组二
// \d \2 对应 1
// 分组三
// \d\d \3 对应 23
// 分组四
// \d \4 对应3

《看懂火星文(三) 2019.4.3更新 🎉》

10

10示意第10个分组呢?照样1和0?

10示意的是第十个分组

援用不存在的分组

援用不存在的分组不会报错。比方2, 2分组不存在, 2婚配的就是字符串”2″

假如分组背面增加量词

分组背面有量词的话,分组终究捕捉到的数据是末了一次的婚配

var str = '12345'
var reg = /\d+/
var reg1 = /(\d)+/

// ["12345", index: 0, input: "12345", groups: undefined]
str.match(reg)
// ["12345", index: 0, input: "12345", groups: undefined]
str.match(reg1)
// \1 应当是婚配的末了一次效果
var regex = /(\d)+ \1/;
// false
regex.test("12345 1")
// true
regex.test("12345 5") );

非捕捉括号

之前的括号都被称为捕捉型的分组, 捕捉到的组的数据会在API中援用。假如只想运用括号最原始的功用,不在API和反向援用中运用能够运用非捕捉括号。


var str = 'HelloWorld'
var reg1 = /(?:Hello)(?:World)/
var reg2 = /(Hello)(World)/

// ["HelloWorld", index: 0, input: "HelloWorld", groups: undefined]
// 捕捉组的数据不会援用
reg1.exec(str)
// ["HelloWorld", "Hello", "World", index: 0, input: "HelloWorld", groups: undefined]
reg2.exec(str)

示例

完成trim功用

第一种思绪是婚配空格, 然后替代空格为空字符串


var reg = /^\s+|\s+$/g
var str = '  reg '
str.replace(reg, '')

第二种思绪是运用分组把内容提取出来, 举行替代。


var str = '  reg '
var reg = /^\s+(.*)\s+$/g

str.replace(reg, '$1')

假如运用量词, 我们须要运用惰性婚配, 由于(.)s$中(.)的部份会婚配除了末了一个空格以外的其他空格


var str = '  reg '
var reg = /^\s*(.*)\s*$/g

str.replace(reg, '$1')

将每一个单词的首字母转换成大写


var str = 'hello world'

// Hello World
// 我们婚配单词边境后的第一个字母
str.replace(/\b\w{1}/g, function (word) {
  return word.toLocaleUpperCase()
})

婚配成对标签

我们能够运用反向援用, 我们将前面的标签作为分组用括号包起来, 1将会是分组婚配的效果。我们如许就可以保证前后两个标签的范例是一致的


var reg = /<([^>]+)>\w+<\/\1>/

// true
reg.test('<p>123</p>')

// false
reg.test('<p>123</div>')

4月3号更新 🎉🎉🎉🎉🎉🎉

回溯

没有回溯的婚配


var reg = /ab{1,3}c/
var str = 'abbbc'

// 婚配是没有回溯的
reg.test(str)

婚配历程的拆分

《看懂火星文(三) 2019.4.3更新 🎉》

有回溯的婚配


var reg = /ab{1,3}c/
var str = 'abbc'

// 婚配是有回溯的
reg.test(str)

婚配历程的拆分

《看懂火星文(三) 2019.4.3更新 🎉》

婚配b字符的量词是{1,3}。第5步的时刻, 我们须要婚配第3个b的时刻, 效果婚配到了c, 婚配发送了毛病, 然则量词时{1,3}, b{1,3}已婚配完成了。所以会到之前的婚配状况(第6步), 回退状况的历程就被称为回溯。

为何.(通配符)是异常影响效力的?


var reg = /".*"/
var str = '"abc"de'

《看懂火星文(三) 2019.4.3更新 🎉》

.*示意恣意字符的恣意长度, 它会婚配到字符串的末端的部份。然后在逐渐的回溯。直到'”‘婚配'”‘, 所以说通配符是异常低效的。我们在这个例子中能够运用1替代通配符。

罕见的回溯情势

贪欲量词

b{1, 3}会起首尝试婚配bbb, 然后bb, 末了是b。假如还不可则婚配失利。贪欲量词从多往少尝试的历程就是回溯的历程。假如多个贪欲量词在一起时, 前面的贪欲量词会优先婚配。

var str = '12345'
var reg = /(\d{1,3})(\d{2,3})/

// true
reg.test(str)

// ["12345", "123", "45", index: 0, input: "12345", groups: undefined]
reg.exec(str)

惰性量词

惰性量词依旧能够存在回溯的状况


var reg = /^\d{1,3}?\d{1,3}$/

var str = '12345'

《看懂火星文(三) 2019.4.3更新 🎉》

为了满足团体的婚配, 只能给只须要婚配1个的惰性量词, 婚配两个字符。 组成回溯。

分支组织

当/分支1|分支2|分支3/, 当分支1不满足会尝试分支2,分支2不满足会尝试分支3。这类尝试也是回溯的一种

正则表达式的拆分

操纵符的优先级

操纵标记操纵符优先级
转义符\1
括号和方括号(…)、(?:…)、(?=…)、(?!…)、[…]2
量词限定符{m}、{m,n}、{m,}、?、*、+3
位置和序列^、$、元字符、平常字符4
管道符(竖杠)5

var reg = /ab?(c|de*)+|fg/
  1. (c|de*)是一个团体
  2. de*中, e作为一个团体
  3. c|de*中,c和de是差异的团体
  4. ab?(c|de)+|fg中, ab?(c|de)+和fg作为差异的团体

《看懂火星文(三) 2019.4.3更新 🎉》

注重要点

婚配字符串团体题目


// ^abc 和 bcd$ 是两个差异的团体
var reg1 = /^abc|bcd$/

// 能够经由历程括号把(abc|bcd)作为同一个团体
var reg2 = /^(abc|bcd)$/

《看懂火星文(三) 2019.4.3更新 🎉》

《看懂火星文(三) 2019.4.3更新 🎉》

量词联缀题目

/^[abc]{3}+$/会发生毛病🙅, 量词没法对量词运用。我们能够运用括号/^([abc]{3})+$/, 将([abc]{3})作为一个团体。

元字符转义题目

在正则表达式中, 元字符由于具有特别的寄义。所以假如须要婚配元字符自身, 必需对元字符转义。

正则表达式中的元字符, ^、$、.、*、+、?、|、、/、(、)、[、]、{、}、=、!、:、-

字符组中的元字符

假定我们须要婚配一组字符, ^, +, ?

2的寄义并非一组字符而是反义字符组。我们必需对^标记举行转义。修改成[^+?]才符合要求。

婚配字符组自身

假如我们须要婚配{2,4}或许[123]呢?

我们能够对两个括号举行转义或许只对一个括号转义, 使它没法组成字符组。修改成{2,4}, 或许{2,4}即可。

案例

IPV4


var reg = /^((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])$/

这个正则看似很庞杂,但我们依据操纵符的优先级,我们能够分为((…).){3}, (…)这两部份。而((…).)中内里的括号实际上是4个分支语句。能够继承拆分。(0{0,2}d|0?d{2}|1d{2}|2[0-4]d|25[0-5])内容能够分红5个分支。

  • 0{0,2}d 婚配1位数, 并补0
  • 0?d{2} 婚配2位数, 并补0
  • 1d{2} 婚配100-199
  • 2[0-4]d 婚配200-249
  • 25[0-5] 婚配250-255

正则表达式的构建

书中本章节更多的是引见, 是不是应当能运用正则, 和是不是有必要运用正则,以及正则效力的题目。有兴致的同砚能够直接去看书。然则我以为本章中,引见了两个正则的例子🌰照样很值得思索🤔的?

婚配牢固电话 ☎️

电话的花样以下055188888888,0551-88888888,(0551)88888888我们该怎样经由历程一个正则举行婚配, 我们将誊写正则历程拆分红几步。

我们起首誊写✍️3种正则离别婚配3种花样的电话号码


var reg1 = /^0\d{2,3}[1-9]\d{6,7}$/
var reg2 = /^0\d{2,3}-[1-9]\d{6,7}$/
var reg3 = /^\(0\d{2,3}\)[1-9]\d{6,7}$/

接下来我们运用或许支解符把3个正则链接为1一个正则表达式


var reg = /^0\d{2,3}[1-9]\d{6,7}$|^0\d{2,3}-[1-9]\d{6,7}$|^\(0\d{2,3}\)[1-9]\d{6,7}$/

我们提交大众的部份


var reg = /^(0d{2,3}|0d{2,3}-|\(0\d{2,3}\))[1-9]\d{6,7}$/

大众部份的第一个分支和第二个分支只差异一个-标记,能够对-运用量词?,还能够进一步简化


var reg = /^(0d{2,3}-?|\(0\d{2,3}\))[1-9]\d{6,7}$/

婚配浮点数

假如经由历程一个正则婚配1.23、+1.23、-1.23 10、+10、-10 .2、+.2、-.2

我们将这些例子分为两种范例, “1.23”、”+1.23″、”-1.23″(有整数位有小数位), “10”、”+10″、”-10″(只要整数位), “.2″、”+.2″、”-.2″(只要小数位)

我们先写三个正则婚配三种范例


var reg1 = /^[-+]?\d+\.\d+$/
var reg2 = /^[-+]?\d+$/
var reg3 = /^[-+]?\.\d+/

我们兼并这三种正则


var reg = /^[-+]?\d+\.\d+$|^[-+]?\d+$|^[-+]?\.\d+/

简化正则


var reg = /^[-+]?(\d+\.\d+|\d+|\.\d+)$/

正则表达式编程

⚠️ 相干API注重要点

match返回效果的花样题目

match接收一个正则表达式作为参数。假如正则表达式中有g标示, 将返回与完整正则表达式婚配的一切效果,但不会返回捕捉组。

假如没有运用g标示,则仅返回第一个完整婚配及其相干的捕捉组。

exec比match更🐂🍺

当正则没有g时,运用match返回的信息比较多。然则有g后,match就没有症结的信息index了(只会返回悉数婚配的内容)。

而exec要领纵然正则包括g,它也能接着上一次婚配后继承婚配。reg的lastIndex会更新(假如不含g不会更新), exec能够合营while运用。


var str = '2019.01.01'

var reg1 = /\./
var reg2 = /\./g

// [".", index: 4, input: "2019.01.01", groups: undefined]
reg1.exec(str)
// 0
reg1.lastIndex

// [".", index: 4, input: "2019.01.01", groups: undefined]
reg2.exec(str)
// 5
reg2.lastIndex

// [".", index: 4, input: "2019.01.01", groups: undefined]
str.match(reg1)
// 0
reg1.lastIndex

// [".", "."]
str.match(reg2)
// 0
reg2.lastIndex

修饰符 g,对exec和test的影响

字符串的要领, 每次婚配后不会影响正则对象的lastIndex属性的值

exec和test要领, 在全局婚配下会影响正则对象的lastIndex, 假如找不到了lastIndex会重置为0

exec和test要领, 假如正则没有g, lastIndex不会转变

结语

📖看到这里也完毕了, 人人假如有兴致能够看原书, 书自身是开源免费的, 很精简80多页

  1. +?
    原文作者:张越
    原文地址: https://segmentfault.com/a/1190000018749258
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞