ES6第六章正则的扩展

ES6第六章

  • EegExp构造函数

    第一种情况是: 参数是字符串,这时第二个参数表示正则表达式的修饰符(flag)。
    var regex = new RegExp('xyz', 'i'); // 等价于 var regex = /xyz/i;
    第二种情况是,参数是一个正则表示式,这时会返回一个原有正则表达式的拷贝。在ES5中当第一个参数是正则表达式时,不支持第二个参数
    如果RegExp构造函数第一个参数是一个正则对象,那么可以使用第二个参数指定修饰符。而且会忽略原有的正则表达式的修饰符,只使用新指定的修饰符。

  • 字符串的正则方法

    match()、replace()、search()和split()ES6 将这 4 个方法,在语言内部全部调用RegExp的实例方法

  • u 修饰符

    对于码点\uFFFF的字符用u后缀才能正确识别。例如: /^\uD83D/u.test(’\uD83D\uDC2A’) // false
    /^\uD83D/.test(’\uD83D\uDC2A’) // true`

    • Unicode 字符表示法
      正则表达式中必须加上u修饰符,才能识别当中的大括号,否则会被解读为量词。
      	/\u{61}/.test('a') // false  
      	/\u{61}/u.test('a') // true
      
    • 预定义模式
      u修饰符也影响到预定义模式,能否正确识别码点大于0xFFFF的 Unicode 字符。
      /^\S$/.test('𠮷') // false
      /^\S$/u.test('𠮷') // true
      
    • i 修饰符
      i 修饰符用于执行对大小写不敏感的匹配
      /[a-z]/i.test('\u212A') // false
      /[a-z]/iu.test('\u212A') // true
      
    • 转义
      没有u修饰符的情况下,正则中没有定义的转义(如逗号的转义,)无效,而在u模式会报错。
      	/\,/        // /\,/
      	/\,/u       // 报错
      
  • RegExp.prototype.unicode属性
    正则实例对象新增unicode属性,表示是否设置了u修饰符
  • y 修饰符
    • y修饰符的作用与g修饰符类似,也是全局匹配,后一次匹配都从上一次匹配成功的下一个位置开始。不同之处在于,g修饰符只要剩余位置中存在匹配就可,而y修饰符确保匹配必须从剩余的第一个位置开始。
      var s = 'aaa_aa_a';
      var r1 = /a+/g;
      var r2 = /a+/y;
      r1.exec(s) // ["aaa"]		剩余字符串 ”_aa_a“
      r2.exec(s) // ["aaa"]       剩余字符串 ”_aa_a“
      r1.exec(s) // ["aa"]		剩余字符串中全局匹配
      r2.exec(s) // null			从第一个字符开赛开始匹配
      
      事实上,y修饰符号隐含了头部匹配的标志^。
      	const TOKEN_Y = /\s*(\+|[0-9]+)\s*/y;
      	const TOKEN_G  = /\s*(\+|[0-9]+)\s*/g;
      	tokenize(TOKEN_Y, '3x + 4')
      	// [ '3' ]		
      	tokenize(TOKEN_G, '3x + 4')				
      	// [ '3', '+', '4' ]		g修饰符会忽略非法字符
      	function tokenize(TOKEN_REGEX, str) {
      		  let result = [];
      		  let match;
      		  while (match = TOKEN_REGEX.exec(str)) {
      		    result.push(match[1]);
      		  }
      		  return result;
      		}
      
  • RegExp.prototype.sticky 属性
    表示是否设置了y修饰
    var r = /hello\d/y;
    r.sticky // true
    
  • RegExp.prototype.flags 属性
    返回正则表达式的修饰符
    	/abc/ig.source
    	// "abc"		ES5
    	/abc/ig.flags
    	// 'gi'       ES6
    
  • s 修饰符:dotAll 模式

    (.)是一个特殊字符,可以代表任意的单个字符,但是有两个例外。一个是四个字节的 UTF-16 字符,这个可以用u修饰符解决;另一个是行终止符(该字符表示一行的终结)U+000A 换行符(\n),U+000D 回车符(\r),U+2028 行分隔符(line separator),U+2029 段分隔符(paragraph separator)

    	/foo.bar/.test('foo\nbar')
    	// false
    	/foo[^]bar/.test('foo\nbar')
    	// true
    	/foo.bar/s.test('foo\nbar')
        // true
    
    dotAll属性,返回一个布尔值,表示该正则表达式是否处在dotAll模式。
    	const re = /foo.bar/s;
    	// 另一种写法
    	// const re = new RegExp('foo.bar', 's');
    	re.test('foo\nbar') // true
    	re.dotAll // true
    	re.flags // 's'
    
  • 后行断言
    • JavaScript 语言的正则表达式,只支持先行断言(lookahead)和先行否定断言(negative lookahead),不支持后行断言(lookbehind)和后行否定断言(negative lookbehind)。ES2018 引入后行断言,V8 引擎 4.9 版(Chrome 62)已经支持。

    • “先行断言”指的是,x只有在y前面才匹配,必须写成/x(?=y)/
    • “先行否定断言”指的是,x只有不在y前面才匹配,必须写成/x(?!y)/。
    	/\d+(?=%)/.exec('100% of US presidents have been male')  // ["100"]
    	/\d+(?!%)/.exec('that’s all 44 of them')                 // ["44"]
    
    • “后行断言”正好与“先行断言”相反,x只有在y后面才匹配,必须写成/(?<=y)x/
    • “后行否定断言”则与“先行否定断言”相反,x只有不在y后面才匹配,必须写成/(?<!y)x/。
      /(?<=\$)\d+/.exec('Benjamin Franklin is on the $100 bill') // ["100"]
      /(?<!\$)\d+/.exec('it’s is worth about €90')       // ["90"]
      
      “后行断言”的实现,需要先匹配/(?<=y)x/的x,然后再回到左边,匹配y的部分。这种“先右后左”的执行顺序,与所有其他正则操作相反,导致了一些不符合预期的行为。
      /(?<=(\d+)(\d+))$/.exec('1053') // ["", "1", "053"]
      /^(\d+)(\d+)$/.exec('1053') // ["1053", "105", "3"]
      
      “后行断言”的反斜杠引用,也与通常的顺序相反,必须放在对应的那个括号之前。
      /(?<=(o)d\1)r/.exec('hodor')  // null
      /(?<=\1d(o))r/.exec('hodor')  // ["r", "o"] 反斜杠引用(\1)必须放在()前面才可以
      
  • Unicode 属性类

    ES2018 引入了一种新的类的写法\p{…}和\P{…},允许正则表达式匹配符合 Unicode 某种属性的所有字符。

    \p{UnicodePropertyName=UnicodePropertyValue}	//Unicode 属性类要指定属性名和属性值。
    
    const regexGreekSymbol = /\p{Script=Greek}/u;		//匹配一个希腊字母
    regexGreekSymbol.test('π') // true
    
    \P{…}是\p{…}的反向匹配,即匹配不满足条件的字符。
    
    // 匹配所有数字
    const regex = /^\p{Number}+$/u;
    regex.test('²³¹¼½¾') // true
    regex.test('㉛㉜㉝') // true
    regex.test('ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ') // true
    
    // 匹配所有空格
    \p{White_Space}
    
    
    // 匹配 Emoji
    /\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F/gu
    
  • 具名组匹配
    • ES2018 引入了具名组匹配(Named Capture Groups),允许为每一个组匹配指定一个名字,既便于阅读代码,又便于引用。
      const RE_DATE = /(?\d{4})-(?\d{2})-(?\d{2})/;

      const matchObj = RE_DATE.exec('1999-12-31');
      const year = matchObj.groups.year; // 1999
      const month = matchObj.groups.month; // 12
      const day = matchObj.groups.day; // 31
      
  • 解构赋值和替换
    • 可以使用解构赋值直接从匹配结果上为变量赋值
      let {groups: {one, two}} = /^(?<one>.*):(?<two>.*)$/u.exec('foo:bar');
      one  // foo
      two  // bar
      
  • 引用
    • 如果要在正则表达式内部引用某个“具名组匹配”,可以使用\k<组名>的写法。
      const RE_TWICE = /^(?<word>[a-z]+)!\k<word>$/;
      RE_TWICE.test('abc!abc') // true
      RE_TWICE.test('abc!ab') // false
      
  • 正则匹配索引
    • 由于正则匹配结果的开始位置和结束位置,目前获取并不是很方便。正则实例的exec()方法,返回结果有一个index属性,可以获取整个匹配结果的开始位置,但是如果包含组匹配,每个组匹配的开始位置,很难拿到。
      第三阶段提案,为exec()方法的返回结果加上indices属性,在这个属性上面可以拿到匹配的开始位置和结束位置。

    	const text = 'zabbcdef';
    	const re = /ab/;
    	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 ] }
    
    如果获取组匹配不成功,indices属性数组的对应成员则为undefined,indices.groups属性对象的对应成员也是undefined。
    	const text = 'zabbcdef';
    	const re = /ab+(?<Z>ce)?/;
    	const result = re.exec(text);
    	result.indices[1] // undefined
    	result.indices.groups['Z'] // undefined
    
  • String.prototype.matchAll()
    • String.prototype.matchAll()方法,可以一次性取出所有匹配。不过,它返回的是一个遍历器(Iterator),而不是数组。
    const string = 'test1test2test3';
    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"]
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值