ES6学习笔记5--正则的扩展

  • RegExp 构造函数

        RegExp语法详解MDN

\p{...} 和 \P{...} 允许正则表达式匹配符合Unicode某种属性的所有字符。只对Unicode字符有效。

使用时请加上 u 修饰符。

/* \p{...}  小写p 反向匹配\P{...}*/
const regexGreekSymbol = /\p{Script=Greek}/u;
regexGreekSymbol.test('π') // true

/* \P{...}  大写P,反向匹配\p{...}*/ 
const regexGreekSymbol = /\P{Script=Greek}/u;
regexGreekSymbol.test('π') //false
##Unicode 属性类要指定属性名和属性值。

\p{UnicodePropertyName=UnicodePropertyValue}

##对于某些属性,可以只写属性名,或者只写属性值。

\p{UnicodePropertyName}
\p{UnicodePropertyValue}

\P{…}是\p{…}的反向匹配,即匹配不满足条件的字符
/*正则表达示例*/

/*属性类指定匹配所有十进制字符*/
const regex = /^\p{Decimal_Number}+$/u;
regex.test('𝟏𝟐𝟑𝟜𝟝𝟞𝟩𝟪𝟫𝟬𝟭𝟮𝟯𝟺𝟻𝟼') // true

/*属性类匹配所有数字,包括罗马数字*/
const regex = /^\p{Number}+$/u;
regex.test('²³¹¼½¾') // true
regex.test('㉛㉜㉝') // true
regex.test('ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ') // true

/* 匹配所有空格 */
const regex = /\p{White_Space}/u

/* 匹配各种文字的所有字母,等同于 Unicode 版的 \w */
const regex =/[\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]/u

/* 匹配各种文字的所有非字母的字符,等同于 Unicode 版的 \W */
const regex =/[^\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]/u

/* 匹配 Emoji*/
const regex = /\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F/gu

/* 匹配所有的箭头字符*/
const regexArrows = /^\p{Block=Arrows}+$/u;
regexArrows.test('←↑→↓↔↕↖↗↘↙⇏⇐⇑⇒⇓⇔⇕⇖⇗⇘⇙⇧⇩') // true
  • 具名组匹配

正则表达式使用圆括号进行组匹配。使用 exec()方法可以将匹配结果取出来

具名组匹配 允许为每一个组指定一个名字,便于阅读以及引用

具名组匹配在模式的头部添加 "问号+尖括号+组名"(?<组名>),即可以在 exec()方法返回结果的 groups 属性上引用该组名

具名组匹配等于为每一组匹配加上 ID,如果组的顺序变了,也无需改变匹配后的处理代码。

/*组匹配*/
const RE_DATE = /(\d{4})-(\d{2})-(\d{2})/;
const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj[1]; // 1999
const month = matchObj[2]; // 12
const day = matchObj[3]; // 31

/*具名组匹配*/
const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const matchObj = RE_DATE.exec('1999-12-31');
const year  = matchObj.groups.year ; //1990
const month = matchObj.groups.month; //12
const day = matchObj.groups.day; //31

具名匹配后可以使用解构赋值直接为变量赋值。以及在字符串替换时使用 $<组名>引用具名组。

具名匹配后可以在正则表达式内部引用某个"具名组匹配",可以使用 \k<组名> 的写法或使用数字引用(\1)依然有效。

/*解构赋值*/
let {groups:{one,two}} = /^(?<one>.*):(?<two>.*)$/u.exec('foo:bar');
one  //foo
two  //bar

/*字符串替换,使用 $<组名>引用具名组*/
let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
'2020-12-25'.replace(re,'$<day>/$<month>/$<year>')  //"25/12/2020"

/*\k<组名>引用*/
const RE_TWICE = /^(?<word>[a-z]+)!\k<word>$/;
RE_TWICE.test('abc!abc') // true
RE_TWICE.test('abc!ab') // false

/*数字引用*/
const RE_TWICE = /^(?<word>[a-z]+)!\1$/;
RE_TWICE.test('abc!abc') // true
RE_TWICE.test('abc!ab') // false

/*\k<组名>引用 与数字引用同时使用*/
const RE_TWICE = /^(?<word>[a-z]+)!\k<word>!\1$/;
RE_TWICE.test('abc!abc!abc') // true
RE_TWICE.test('abc!abc!ab') // false
  • 正则匹配索引(了解即可)

获取正则匹配结果的开始位置和结束位置。

exec() 方法提供 index属性以及indices 属性(处于第三阶段提案中)。可以获取到匹配的开始位置和结束位置。

注意:开始位置包含在匹配结果之中,但是结束位置不包含在匹配结果之中

const text = 'zabbcdef';
const re = /bc/;
const result = re.exec(text);

result.index // 1
result.indices // [ [1, 3] ]

/*如果正则表达式包含组匹配,那么indices 属性对应的数组就会包含多个成员,
提供每个组匹配的开始位置和结束位置。*/

const text = 'zabbcdef';
const re = /ab+(cd)/;
const result = re.exec(text);
result.indices // [ [ 1, 6 ], [ 4, 6 ] ]

/*如果正则表达式包含具名匹配,indices 属性数组还会有一个groups 属性。该属性是一个对象。
可以从该对象获取具名匹配的开始位置和结束位置*/

const text = 'zabbcdef';
const re = /ab+(?<Z>cd)/;
const result = re.exec(text);
result.indices.groups // { Z: [ 4, 6 ] }
  • String.prototype.matchAll()

String.prototype.matchAll() 方法可以一次性取出所有匹配,返回一个遍历器,而不是数组。

可以使用 for...of 循环取出/或使用 ...运算符以及Array.from()转换为数组。

const string = 'test1test2test3';
// g 修饰符加不加都可以
const regex = /t(e)(st(\d?))/g;
for (const match of string.matchAll(regex)) {
  console.log(match);
}
// ["test1", "e", "st1", "1", index: 0, input: "test1test2test3"]
// ["test2", "e", "st2", "2", index: 5, input: "test1test2test3"]
// ["test3", "e", "st3", "3", index: 10, input: "test1test2test3"]


// 转为数组方法一
[...string.matchAll(regex)]
// 转为数组方法二
Array.from(string.matchAll(regex))
  • RegExp.prototype.unicode属性

RegExp.prototype.unicode 属性表示是否设置了 u 修饰符

const r1 = /hello/;
const r2 = /hello/u;
r1.unicode //false;
r2.unicode // true;
  •  y 修饰符与 g 修饰符比较

y 修饰符 "粘连"修饰符。与 g 修饰符类似,也是全局匹配。后一次匹配从上一次匹配成功的下一个位置开始。

不同之处在于 g 修饰符只要剩余位置中存在匹配就可。而 y 修饰符确保匹配必须从剩余的第一个位置开始。

var s = 'aaa_aa_a';
var r1 = /a+/g;
var r2 = /a+/y;

r1.exec(s) //["aaa"]
r2.exec(s) // ["aaa"]

r1.exec(s) // ["aa"]
r2.exec(s) // null

/*使用lastIndex 属性说明  y 修饰符与 g 修饰符*/

/* g 修饰符,lastIndex 属性指定每次搜索的开始位置,
g 修饰符从这个位置开始向后搜索,知道发现匹配为止 */

const REGEX = /a/g;  //此时lastIndex =0 ;
//我们设置指定从2号位置(y) 开始匹配
REGEX.lastIndex = 2;
//匹配成功
const match = REGEXP.exec("xaya");
//在3号匹配成功
match.index //3
//下一次匹配从4号开始
match.lastIndex //4
// 4 号为开始匹配失败
REGEXP.exec('xaya'); //null,lastIndex属性归为0; 

/* y 修饰符,lastIndex 属性指定每次搜索的开始位置,但必须在 lastIndex 指定的位置发现匹配.
y 修饰符隐含了头部匹配的标志 ^
*/
const REGEX = /a/y;
//我们设置指定从2号位置(y) 开始匹配
REGEX.lastIndex = 2;
// 不是粘连,匹配失败
REGEX.exec('xaya') // null
// 指定从3号位置开始匹配
REGEX.lastIndex = 3;
const match = REGEX.exec('xaya');
match.index // 3
REGEX.lastIndex // 4

y 修饰符使用 match() 方法,只能返回第一个匹配。必须与 g 修饰符 联用,才能返回所有匹配

'a1a2a3'.match(/a\d/y) // ["a1"]
'a1a2a3'.match(/a\d/gy) // ["a1", "a2", "a3"]
  • RegExp.prototype.sticky 属性

y修饰符相匹配,ES6 的正则实例对象多了sticky属性,表示是否设置了y修饰符。

var r = /hello\d/y;
r.sticky // true
  • RegExp.prototype.flags 属性

//ES6 为正则表达式新增了flags属性,会返回正则表达式的修饰符。

// ES5 的 source 属性
// 返回正则表达式的正文
/abc/ig.source
// "abc"
// ES6 的 flags 属性
// 返回正则表达式的修饰符
/abc/ig.flags
// 'gi'
  • s 修饰符:dotAll 模式

正则表达是中, 点( . ) 是一个特殊字符,可以代表任意的单个字符。但是有两个例外。

一个是 四个字节的UTF-16 字符,可以用 u 修饰符解决。

另一个是 行中止符。

  • U+000A 换行符(\n
  • U+000D 回车符(\r
  • U+2028 行分隔符(line separator)
  • U+2029 段分隔符(paragraph separator)

ES5 中 匹配任意字符写法:

/foo.bar/.test('foo\nbar')  //false 无法匹配 \n 换行符

/*变通写法*/
/foo[^]bar/.test('foo\nbar') // true

ES6 引入 s 修饰符,使得 . 可以匹配单个字符。这种模式被称为 dotAll 模式,即 点(dot)代表一切字符。

还引入 dotAll 属性,返回一个布尔值,表示该正则表达式是否处于 dotAll 模式。

/foo.bar/s.test('foo\nbar') // true

/foo.bar/s.dotAll //true
/foo.bar/s.flags //'s'

补充:

"先行断言": x 只有在 y 前面才匹配,必须写成 /x(?=y)/  仅仅当 x 后面跟着 y 时匹配 x

例子:只匹配百分号之前的数字,要写成   /\d+(?=%)/

/\d+(?=%)/.exec('100% of US presidents have been male')  // ["100"]

"先行否定断言"x 只有不在 y 前面匹配,必须写成 /x(?!y)/ 仅仅当 x 后面 不是 y 时匹配 'x'

例子:只匹配不在百分号之前的数字,要写成  /\d+(?!%)/

/\d+(?!%)/.exec('that’s all 4% 88 of them')  //['88']

"后行断言"x 只有在 y 后面才匹配,必须写成 /(?<=y)x/  仅仅当 x 前面是 y 时 匹配 x 

例子:只匹配美元符号之后的数字,要写成  /(?<=\$)\d+/

/(?<=\$)\d+/.exec('Benjamin Franklin is on the $100 bill') // ["100"]

 "后行否定断言": x 只有不在 y 后面才匹配,必须写成  /(?<!y)x/  仅仅当 x 前面不是 y 时匹配 x

例子:只匹配不在美元符号后面的数字,要写成   /(?<!\$)\d+/

/(?<!\$)\d+/.exec('it’s is worth about $5 €90') ["90"]

 

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值