【ES6】2.字符串、正则

1.字符串的扩展

1.字符的Unicode表示法

JS允许使用\uxxxx表示一个字符,xxxx表示码点,该方法只适用于\u0000——\uFFFF区间的字符,在ES6中,给码点加个大括号就可以解决,如:\u{7A}

2.字符串的遍历

使用for…of可以遍历字符串

const str = 'hello'
for (let a of str) {
    console.log(a) // h e l l o
}

3.模板字符串

  • 用反引号(`)表示,
  • 可以定义多行变量,
  • 可以嵌入变量${},
  • 所有空格会被保留,如果要去掉首尾空格可以用trim()方法,
  • 模板字符串可以嵌套。
// 可以定义多行变量
const str = `1
233`
// 可以嵌入变量
const a = 5;
const str = `这个数是${a}`
// 去掉空格
const str = (`   11212234234  `).trim()
// 模板字符串可以嵌套
const str = `112245${`rtrfg`}wee`

4.模板标签

  • 标签模板其实不是模板,而是函数调用的一种特殊形式。“标签”指的就是函数,紧跟在后面的模板字符串就是它的参数。
    alert`hello` // 等同于alert['hello']
  • 如果模板字符串有变量,会先将模板字符串处理成多个参数,在调用函数。
  • 是否变空字符的说明:位于两个非变量之间的变量不会变成空字符,如:假设A是变量,B不是变量
    ABA => ([’’, ‘B’, ‘’], A, A)
    BAB => ([‘B’, ‘B’], A)
    ABAB => ([’’, ‘B’, ‘B’], A, A)
let a = 5;
let b = 10;
tag`Hello ${ a + b } world ${ a * b }`;
// 第一个变量处于两个非变量之间,所以不会变成空字符,第二个变量右边没有非变量,所以变空字符
// 等同于,
tag(['Hello', ' world', ''], 15, 50)
let a = 5;
let b = 10;
function tag(s, v1, v2) {
  // s = ['Hello', ' world', '']
  // 整个参数(['Hello', ' world', ''], a+b=15, a*b=50)
  console.log(s[0]); // Hello
  console.log(s[1]); //  world
  console.log(s[2]); // ''
  console.log(v1); // 15
  console.log(v2); // 50
  return "OK";
}
tag`Hello ${ a + b } world ${ a * b}`;
  • 模板标签的重要应用:过滤 HTML 字符串,防止用户输入恶意内容
  • 模板标签的另一个应用:多语言转换(国际化处理)

2.字符串新增的方法

1.String.fromCodePoint()

  • 用于从Unicode码点返回对应的字符串
    String.fromCharCode(0x20BB7) // "ஷ"

2.String.raw()

  • 该方法返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,往往用于模板字符串的处理方法
String.raw`Hi\n${2+3}!`
// 实际返回 "Hi\\n5!",显示的是转义后的结果 "Hi\n5!"

3.repeat() 重复字符串方法

const str = 'x'
str.repeat(3) // xxx
// 如果参数是小数,会被向下取整
str.repeat(0.3) // 空值
// 如果参数是0到-1之间的小数,则等同于0,因为先取整取到0
str.repeat(-0.3) // 空值
// 如果参数是小于-1负数或者Infinity(无穷),会报错
str.repeat(-2) // 报错
str.repeat(Infinity) // 报错
// 参数NaN等同于0
str.repeat(NaN) // 空值
// 参数是字符串,则会先转换成数字
str.repeat('5') // xxxxx

4.includes()

  • 返回布尔值,表示是否找到了参数字符串。
let s = 'Hello world!';
s.includes('o') // true

5.startsWidth()

  • 返回布尔值,表示参数字符串是否在原字符串的头部。
let s = 'Hello world!';
s.startsWith('He') // true
s.startsWith('Hello') // true

6.endsWidth()

  • 返回布尔值,表示参数字符串是否在原字符串的尾部。
let s = 'Hello world!'
s.endsWith('!') // true

7.padStart() padEnd()

  • 字符串补全长度功能,padStart()补全在头部,padEnd()补全在尾部。两个方法都是接收两个参数,第一个参数是字符串目标补全长度,第二个参数是用来补全的字符串。
'1'.padStart(5, '0') // 00001
'1'.padEnd(5, '0') // 10000
// 如果原字符串的长度大于或等于目标长度,则还原字符串
'10'.padStart(4, '0') // 0010
// 如果用来补全的字符串与原字符串的长度和大于目标长度,则会截去用来补全的字符串的超出部分
'12345'.padStart(6, 'abcdef') // a12345
// 如果省略第二个参数,则会用空字符补全
'1234'.padEnd(6) // '1234  '
  • 常见用途:
    1.用来补全位数,如指定位数必须为10,其余用0补充
    '100'.padStart(10, '0') // 0000000100
    2.提示字符串格式
'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"
'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"

8.trimStart() trimEnd()

  • trimStart()消除字符串头部空格、tab缩进、换行等空白
  • trimEnd()消除字符串尾部空格、tab缩进、换行等空白

9.replaceAll()

  • 与replace()用法一致,但是replace只能替换第一个匹配的字符,而replaceAll可以替换所有匹配的字符。
'abbdc'.replace('b', '-') // a-bdc
'abbdc'.replaceAll('b', '-') // a--bdc

3.正则的扩展

1.正则表达式的修饰符

1.i修饰符

ignore - 不区分大小写。

2.g修饰符

global - 全局匹配,查找所有的匹配项。

3.m修饰符

multi line - 多行匹配

4.y修饰符(es6新增)

sticky - ‘粘连’修饰符。y修饰符与g修饰符相似,都是全局匹配,后一次匹配从上一次匹配成功的下一个位置开始。
区别是:g修饰符只要剩余位置中存在匹配即可;而y修饰符必须从剩余的第一个位置开始匹配。

const str = 'aaa_aa_a'
const r1 = /a+/g
const r2 = /a+/y
r1.exec(str) // ['aaa']
r2.exec(str) // ['aaa']
// 第一次执行结果相同,剩余部分都是'_aa_a'
r1.exec(str) // g修饰只要剩余部分存在匹配就可 ['aa']
r2.exec(str) // y修饰要求必须从剩余部分的第一项开始匹配 null
// 如果修改字符串,保证每次都能头部匹配,则可以返回结果
const r = /a+_/y   // 匹配a_
r.exec(str) // ['aaa_'], 剩余'aa_a'
r.exec(str) // ['aa_']

5.u修饰符(es6新增)

unicode - Unicode字符。

  • 点字符
    点(.)字符在正则表达式中,含义是除了换行符以外的所有单个字符。对于码点大于0xFFFF的Unicode字符,点字符不能识别,必须加上u字符。
var s = '𠮷';
/^.$/.test(s) // false // 不加u,正则表达式认为是两个字符,因此匹配失败
/^.$/u.test(s) // true
  • Unicode字符表示法
    ES6新增了使用大括号表示Unicode字符(如\u{61}表示a),这种表示法在正则表达式中必须加上u字符,否则大括号中的内容会被人为是量词。
/\u{61}/.test('a') // false 没有加u,被认为是匹配连续的61个u
/\u{61}/u.test('a') // true \u{61}是Unicode字符,值为a
/\u{20BB7}/u.test('𠮷') // true
  • 量词
    使用u修饰后,所有量词都会正确识别码点大于0xFFFF的Unicode字符。
/a{2}/.test('aa') // true  匹配两个a
/a{2}/u.test('aa') // true 匹配两个a
/𠮷{2}/.test('𠮷𠮷') // false 匹配两个𠮷,没有加u修饰,无法识别码点大于0xFFFF
/𠮷{2}/u.test('𠮷𠮷') // true 匹配两个𠮷
  • 预定义模式
    u修饰符也影响到预定义模式,能否正确识别码点大于0xFFFF的Unicode字符。
// \S是预定义模式,匹配所有非空字符。
/^\S$/.test('𠮷') // false 未加u修饰,不能识别码点大于0xFFFF的字符。
/^\S$/u.test('𠮷') // true 加了u修饰,可以识别

// 正确返回字符串长度的函数
function codePointLength(text) {
    // [\s\S]表示识别所有字符,\s识别所有空字符(包括tab、换行等),\S识别所有非空字符
  var result = text.match(/[\s\S]/gu); 
  return result ? result.length : 0;
}
var s = '𠮷 𠮷';
s.length // 5
codePointLength(s) // 3
  • i修饰符
    有些Unicode字符的编码不同,但是字型很接近,如:\u0048\u212A都是大写的K
/[a-z]/i.test('\u212A') // false \u212A超过0xFFFF,未加u无法正确识别
/[a-z]/iu.test('\u212A') // true
  • 转义
    没有\u修饰符的情况下,正则中没有定义的转义(如逗号的转义\,)无效,而在u模式会报错。
/\,/ // /\,/  没有u修饰符,逗号前面的反斜杠是无效的
/\,/u // 报错  加了u修饰,报错

2.RegExp构造函数

  • 在ES5中,RegExp构造函数的参数只有两种情况:
const reg = new RegExp('xyz', 'i') // 参数是字符串,需传两个参数,第二个参数是修饰符
const reg = new RegExp(/xyz/i) // 参数是正则表达式,只需要传一个参数
// 以上两种情况都等价于 const reg = /xyz/i
const reg = new RegExp(/xyz, 'i') // 报错
  • 在ES6中,参数为正则表达式时,也可以传两个参数,第二个参数为修饰符,而且优先级更高,第二个修饰符会覆盖前面的修饰符。
const reg = new RegExp(/xyz/ig, 'i') // 第二个参数i对覆盖原有的修饰符/ig

3.RegExp.prototype.unicode 属性

与u修饰符相匹配,表示是否用了u修饰符。

const r1 = /hi/
const r2 = /hi/u
r1.unicode // false 没有使用u修饰
r2.unicode // true 使用了u修饰

4.RegExp.prototype.sticky属性

与y修饰符相匹配,表示是否使用了y修饰符。

const r = /hi/y
r.sticky // true

5.RegExp.prototype.flags属性

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

const r = /hi/ig
// ES5的source属性 返回正则表达式的正文
r.source // 'hi'
// ES6的flags属性 返回正则表达式的修饰符
r.flags // 'gi'

6.后行断言(ES2018引入)

  • JS的正则表达式支持先行断言(lookahead)和先行否定断言(negative lookahead)。
  • 先行断言:指x只有在y前面才匹配,必须写成/x(?=y)/,如匹配百分比之前的数字:/\d+(?=%)/
  • 先行否定断言:指x只有不在y前面才匹配,必须写成/x(?!y)/,如匹配不在百分号之前的数字:/\d+(?!%)/
/\d+(?=%)/.exec('100% of US presidents have been male')  // 匹配百分号之前的数字["100"]
/\d+(?!%)/.exec('that’s all %44 of them')                 // 匹配百分号之后的["44"]
  • 后行断言:x只有在y后面才匹配,必须写成/(?<=y)x/,如匹配美元符号之后的数字:/(?<=\$)\d+/
  • 后行否定断言:x只有不在y后面才匹配,必须写成/(?<!y)x/,如匹配不在美元符号后面的数字:/(?<!\$)\d+/
const str= 'xxx 547$ sssd $012'
console.log(`匹配美元之后的数字:${(/(?<=\$)\d+/).exec(str)}`); // 012
console.log(`匹配不在美元之后的数字:${(/(?<!\$)\d+/).exec(str)}`); // 547
// 使用后行断言进行字符串替换
const RE_DOLLAR_PREFIX = /(?<=\$)foo/g;  // 匹配美元符$之后的foo
'$foo %foo foo'.replace(RE_DOLLAR_PREFIX, 'bar'); // $bar %foo foo 将匹配结果替换成bar

7.具名组匹配(ES2018引入)

正则表达式使用圆括号进行组匹配。ES2018引入具名组匹配,允许为每一个组匹配指定一个名字。格式是/(?<name1>\d{4})-(?<name2>\d{2})-(?<name3>\d{2})/,在回结果groups属性通过名称(ame1、name2…)获取匹配结果。

// 以下这种方法对顺序有要求
const RE_DATE = /(\d{4})-(\d{2})-(\d{2})/;
const str = '2021-03-04'
RE_DATE.exec(str) // ['2021', '03', '04']
// 具名组匹配
const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const str = '2021-03-04'
const result = RE_DATE.exec(str)
result.groups.year // '2021'
result.groups.month // '03'
result.groups.day // '04'
// 使用解构赋值
const { groups: { year, month, day}} = result // year='2021' month='03' day='04'
// 替换
'2021-03-04'.replace(RE_DATE, '$<day>/$<month>/$<year>') // 04/03/2021 第二个参数是字符串

8.String.prototype.matchAll()(ES2020新增)

ES2020新增的方法,可以一次性取出所有匹配值,返回的是一个遍历器(Iterator),而不是数组。原本的g和y修饰符虽然是全局匹配,但是需要放在循环里面多次执行,而matchAll()是一次性返回所有匹配结果。

const string = 'test1test2test3'
const r = /t(e)(st(\d?))/g
for (const match of string.matchAll(r)) {
  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"]

遍历器转化为数组:使用...运算符或者Array.from()方法

// 转为数组的方法一
[...string.matchAll(regex)]

// 转为数组的方法二
Array.from(string.matchAll(regex))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值