正则表达式小记

什么是正则表达式

正则表达式是用于婚配字符串中字符组合的形式。在 JavaScript中,正则表达式也是对象。

这些形式被用于
RegExp
exec
test 要领, 以及
String
match
replace
search
split 要领。

正则表达式存在于大部分的编程言语,就算是在写shell时也会不经意的用到正则。
比方人人最喜欢的rm -rf ./*,这里边的*就是正则的通配符,婚配恣意字符。

JavaScript也有正则表达式的完成,差不多就长这个模样:/\d/(婚配一个数字)。
个人认为正则所用到的处所照样许多的,比方模版字符的替代、剖析URL,表单考证 等等一系列。
假如在Node.js中用途就更加多,比方要求头的剖析、文件内容的批量替代以及写爬虫时刻一定会碰到的剖析HTML标签。

《正则表达式小记》

正则表达式在JavaScript中的完成

JavaScript中的语法

赘述那些特别字符的作用并没有什么意义,浪费时候。
引荐MDN的文档:基本的正则表达式特别字符

关于正则表达式,个人认为以下几个比较主要:

贪欲形式与非贪欲形式

P.S. 关于贪欲形式非贪欲形式,发明有些处所会拿如许的例子:

/.+/ // 贪欲形式
/.+?/ // 非贪欲形式

仅仅拿如许简朴的例子来讲的话,有点儿扯淡

// 假设有如许的一个字符串
let html = '<p><span>text1</span><span>text2</span></p>'

// 如今我们要掏出第一个`span`中的文本,因而我们写了如许的正则
html.match(/<span>(.+)<\/span>/)
// 却发明婚配到的竟然是 text1</span><span>text2
// 这是由于 我们括号中写的是 `(.+)` .为婚配恣意字符, +则示意婚配一次以上。
// 当划定规矩婚配到了`text1`的时刻,还会继承查找下一个,发明`<`也掷中了`.`这个划定规矩
// 因而就延续的今后找,晓得找到末了一个span,完毕本次婚配。

// 然则当我们把正则修改成如许今后:
html.match(/<span>(.+?)<\/span>/)
// 此次就能够婚配到我们想要的效果了
// `?`的作为是,婚配`0~1`次划定规矩
// 然则假如跟在`*`、`+`之类的示意数目的特别字符后,寄义就会变成婚配只管少的字符。
// 当正则婚配到了text1后,推断后边的</span>掷中了划定规矩,就直接返回效果,不会今后继承婚配。

简朴来讲就是:

  1. 贪欲形式,能拿<span style=”font-size: 2em;”>若干</span>拿若干
  2. 非贪欲形式,能拿多<span style=”font-size: 2em;”>少</span>拿若干

捕捉组

/123(\d+)0/ 括号中的被称之为捕捉组。

捕捉组有许多的作用,比方处置惩罚一些日期花样的转换。

let date = '2017-11-21'

date.replace(/^(\d{4})-(\d{2})-(\d{2})$/, '$2/$3/$1')

又或许能够直接写在正则表达式中作为前边反复项的婚配。

let template = 'hello helloworl'
template.match(/(\w+) \1/) // => hello hello

// 我们能够用它来婚配出month和day数字雷同的数据
let dateList = `
2017-10-10
2017-11-12
2017-12-12
`

dateList.match(/^\d{4}-(\d{2})-(\1)/gm) // => ["2017-10-10", "2017-12-12"]

非捕捉组

我们读取了一个文本文件,里边是一个名单列表
我们想要掏出一切Stark的名字(然则并不想要姓氏,由于都叫Stark),我们就能够够写如许的正则:

let nameList = `
Brandon Stark
Sansa Stark
John Snow
`

nameList.match(/^\w+(?=\s?Stark)/gm) // => ["Brandon", "Sansa"]

上边的(?=)就黑白捕捉组,意义就是划定规矩会被掷中,然则在效果中不会包括它。

比方我们想完成一个比较经常运用的功用,给数组增加千分位:

function numberWithCommas (x = 0) {
  return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
}

numberWithCommas(123) // => 123
numberWithCommas(1234) // => 1,234

\B代表婚配一个非单词边境,也就是说,现实他并不会替代掉任何的元素。
其次,后边的非捕捉组这么定义:存在三的倍数个数字(3、6、9),而且这些数字后边没有再随着其他的数字。
由于在非捕捉组中运用的是(\d{3})+,贪欲形式,所以就会只管多的去婚配。
假如传入字符串1234567,则第一次婚配的位置在12之间,第二次婚配的位置在45之间。
取得的终究字符串就是1,234,567

怎样运用正则表达式

RegExp对象

建立RegExp对象有两种体式格局:

  1. 直接字面量的声明:/\d/g
  2. 经由过程组织函数举行建立:new RegExp('\d', 'g')

RegExp对象供应了两个要领:

exec

要领实行传入一个字符串,然后对该字符串举行婚配,假如婚配失利则直接返回null
假如婚配胜利则会返回一个数组:

let reg = /([a-z])\d+/
let str = 'a233'
let result = reg.exec(str) // => ['a233', 'a', ...]

P.S. 假如正则表达式有g标识,在每次实行完exec后,该正则对象的lastIndex值就会被转变,该值示意下次婚配的最先下标

let reg = /([a-z])\d+/g
let str = 'a233'
reg.exec(str) // => ['a233', 'a', ...]
// reg.lastIndex = 4
reg.exec(str) // => null
test

要领用来搜检正则是否能胜利婚配该字符串

let reg = /^Hello/

reg.test('Hello World') // => true
reg.test('Say Hello') // => false

test要领一般来讲多用在检索或许过滤的处所。
比方我们做一些挑选filter的操纵,用test就是一个很好的挑选。

// 挑选出一切名字为 Niko的数据
let data = [{ name: 'Niko Bellic' }, { name: 'Roman Bellic'}]

data.filter(({name}) => /^Niko/.test(name)) // => [{ name: 'Niko Bellic' }]

String对象

除了
RegExp对象完成的一些要领外,
String一样供应了一套要领供人人来运用。

search

传入一个正则表达式,并运用该表达式举行婚配;
假如婚配失利,则会返回-1
假如婚配胜利,则会返回婚配最先的下标。
能够理解为是一个正则版的indexOf

'Hi Niko'.search(/Niko/) // => 3
'Hi Niko'.search(/Roman/) // => -1

// 假如传入的参数为一个字符串,则会将其转换为`RegExp`对象
'Hello'.search('llo') // => 2
split

split要领应当是比较经常运用的,用得最多的预计就是[].split(',')了。。

但是这个参数也是能够塞进去一个正则表达式的。

'1,2|3'.split(/,|\|/) // => [1, 2, 3]

// 比方我们要将一个日期时候字符串举行支解
let date = '2017-11-21 23:40:56'

date.split(/-|\s|:/)

// 又或许我们有这么一个字符串,要将它准确的支解
let arr = '1,2,3,4,[5,6,7]'

arr.split(',') // => ["1", "2", "3", "4", "[5", "6", "7]"] 这个效果肯定是不对的。

// 所以我们能够这么写
arr.split(/,(?![,\d]+])/) // => ["1", "2", "3", "4", "[5,6,7]"]

该条划定规矩会婚配,,然则,后边另有一个限制前提,那就是相对不能涌现数字+,的组合而且以一个]末端。
如许就会使[4,5,6]里边的,不被婚配到。

match

match要领用来检索字符串,并返回婚配的效果。

假如正则没有增加g标识的话,返回值与exec相似。
然则假如增加了g标识,则会返回一个数组,数组的item为满足婚配前提的子串。
这将会疏忽掉一切的捕捉组。
拿上边的谁人剖析HTML来讲

let html = '<p><span>text1</span><span>text2</span></p>'

html.match(/<span>(.+?)<\/span>/g) // => ["<span>text1</span>", "<span>text2</span>"]
replace

replace应当是与正则有关的运用最多的一个函数。
最简朴的模版引擎能够基于replace来做。
日期花样转换也能够经由过程replace来做。
以至match的功用也能够经由过程replace来完成(虽然说代码会看起来很丑)

replace吸收两个参数
replace(str|regexp, newStr|callback)

第一个参数能够是一个字符串 也能够是一个正则表达式,转换划定规矩同上几个要领。
第二个参数倒是能够传入一个字符串,也能够传入一个回调函数。

当传入字符串时,会将正则所婚配到的字串替代为该字符串。
当传入回调函数时,则会在婚配到子串时挪用该回调,回调函数的返回值会替代被婚配到的子串。

'Hi: Jhon'.replace(/Hi:\s(\w+)/g, 'Hi: $1 Snow') // => Hi: Jhon Snow

'price: 1'.replace(/price:\s(\d)/g, (/* 婚配的完全串 */str, /* 捕捉组 */ $1) => `price: ${$1 *= 10}`) // => price: 10

一些全新的特征

前段时候看了下
ECMAScript 2018的一些草案,发明有些
Stage 3的草案,其中有提到
RegExp相干的,并在
chrome上实验了一下,发明已能够运用了。

Lookbehind assertions(应当能够叫做回溯援用吧)

一样也是一个非捕捉组的语法定义

语法定义:

let reg = /(?<=Pre)\w/

reg.test('Prefixer') // => true
reg.test('Prfixer') // => false

设置婚配串前边必需满足的一些前提,与(?=)恰好相反,一前一后。
这个结合著(?=)运用简直是神器,照样说剖析HTML的谁人问题。
如今有了(?<=)今后,我们以至能够直接经由过程一个match函数拿到HTML元素中的文本值了。

let html = '<p><span>text1</span><span>text2</span></p>'

html.match(/(?<=<span>)(.+?)(?=<\/span>)/g) // => ["text1", "text2"]

Named capture groups(定名捕捉组)

我们晓得,()标识这一个捕捉组,然后用的时刻就是经由过程\1或许$1来运用。
此次草案中提到的定名捕捉组,就是能够让你对()举行定名,在运用时刻能够用靠近变量的用法来挪用。

语法定义:

let reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/

'2017-11-21'.match(reg)

match的返回值中,我们会找到一个groupskey
里边存储着一切的定名捕捉组。
《正则表达式小记》
《正则表达式小记》

在replace中的用法
let reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
'2017-11-21'.replace(reg, '$<month>/$<day>/$<year>') // => 21/11/2017
表达式中的反向援用
let reg = /\d{4}-(?<month>\d{2})-\k<month>/
reg.test('2017-11-11') // => true
reg.test('2017-11-21') // => false

参考资料

个人GitHub:https://github.com/jiasm

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