• JS高级 之 RegExp - 正则表达式


       

    目录

    ​​​​​​​一、正则表达式

    1. 概念

    2. 创建

    01 - 通过RegExp类来创建

    02 - 通过字面量来创建

    3. 使用方法

    正则对象的实例方法

            01 - exec

            02 - test

    字符串对象的实例方法

            01 - match

            02 - matchAll

            04 - replaceAll

            05 - search

            06 - split

    二、修饰符的使用

    三、规则

    规则 – 字符类(Character classes)

    字符类

            01 - \d 

            02 - \s 

            03 - \w

            04 - . 

    反向类(Inverse classes)

    规则 – 锚点(Anchors)

    01 - ^ && $

    02 - 词边界 \b

    规则 – 转义字符

    规则 – 集合(Sets)和范围(Ranges)

    集合(Sets): 

    范围(Ranges): 

    匹配手机号码

    排除范围

    规则 – 量词(Quantifiers)

    数量 {n}

    缩写:

    栗子一 🌰

    栗子二 🌰

    规则 – 贪婪( Greedy)和惰性( lazy)模式

    贪婪模式 : 

    惰性模式 : 

    规则 – 捕获组(capturing group)

    捕获组

    命名组 

    非捕获组

    或 or

    四、常用正则

    1. 去除字符串空格

    2. 匹配手机号

    3. 歌词解析

    4. 时间格式化


    ​​​​​​​一、正则表达式

    1. 概念

    正则表达式(英语:Regular Expression,常简写为regex、regexp或RE) :

    • 又称正则表示式、正则表示法、规则表达式、常规表示法,是计算机科学的一个概念
    • 正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串
    • 许多程序设计语言都支持利用正则表达式进行字符串操作

    简单概况:正则表达式是一种字符串匹配利器,可以帮助我们搜索、获取、替代字符串

    2. 创建

    正则表达式主要由两部分组成:模式(patterns)和修饰符(flags)

    01 - 通过RegExp类来创建

    1. // 创建正则
    2. // 1> 匹配的规则pattern
    3. // 2> 匹配的修饰符flags
    4. const regex = new RegExp("abc", "ig")

    02 - 通过字面量来创建

    1. // 创建正则
    2. // 1> 匹配的规则pattern
    3. // 2> 匹配的修饰符flags
    4. const regex = /abc/ig

    3. 使用方法

    正则对象的实例方法

            01 - exec

    exec : 一个在字符串中执行查找匹配的 RegExp 方法,它返回一个数组未匹配到则返回 null

     

    通俗的说 : 查找到匹配规则的字符串,并返回相关信息

    1. // 正则 => 匹配abc 全局查找,不区分大小写
    2. const regex = /abc/gi;
    3. // 字符串
    4. const message = 'abc fAbcdaBc cabc 123';
    5. // const res = regex.exec(message);
    6. // console.log(res);
    7. /**
    8. * 每次执行,会返回找到的第一个
    9. * 再执行一次,会在原来基础上继续查找 => 前提是加上了全局查找修饰符g,否则永远找到第一个
    10. */
    11. // ['abc', index: 0, input: 'abc fAbcdaBc cabc 123', groups: undefined]
    12. console.log(regex.exec(message));
    13. // ['Abc', index: 5, input: 'abc fAbcdaBc cabc 123', groups: undefined]
    14. console.log(regex.exec(message));
    15. // ['aBc', index: 9, input: 'abc fAbcdaBc cabc 123', groups: undefined]
    16. console.log(regex.exec(message));
    17. // ['abc', index: 14, input: 'abc fAbcdaBc cabc 123', groups: undefined]
    18. console.log(regex.exec(message));
    19. // null
    20. console.log(regex.exec(message));

            02 - test

    一个在字符串中测试是否匹配的 RegExp 方法,它返回 true 或 false

     

    通俗的说 : 检测某一个字符串是否符合正则的规则

    1. // 正则 => 匹配规则,是否以.()这些结尾
    2. const reg = /\.(AMR|WAV|AWB|mp3|mp4)$/;
    3. // 字符串
    4. const str1 = 'abc.mp3';
    5. const str2 = 'abc.mp4';
    6. const str3 = 'abc.WAV';
    7. const str4 = 'abc.mp6';
    8. console.log(reg.test(str1)); // true
    9. console.log(reg.test(str2)); // true
    10. console.log(reg.test(str3)); // true
    11. console.log(reg.test(str4)); // false

    字符串对象的实例方法

            01 - match

    一个在字符串中执行查找匹配的 String 方法,它返回一个数组,在未匹配到时会返回 null

     

    通俗的说 : 检测某一个字符串是否符合正则的规则,返回查找到的数据

    1. // 正则 => 匹配abc 全局查找,不区分大小写
    2. const regex = /abc/gi;
    3. // 字符串
    4. const message = 'abc fAbcdaBc cabc 123';
    5. /**
    6. * 全局查找时,会把查找到的字符串返回数组
    7. */
    8. // ['abc', 'Abc', 'aBc', 'abc']
    9. console.log(message.match(regex));
    10. // ['abc', 'Abc', 'aBc', 'abc']
    11. console.log(message.match(regex));
    12. // -------------------------------------------------------
    13. // 正则 => 匹配abc ,不区分大小写
    14. const regex1 = /abc/i;
    15. // 字符串
    16. const message1 = 'abc fAbcdaBc cabc 123';
    17. /**
    18. * 只会查找到第一个,不会继续往后查找
    19. */
    20. // ['abc', index: 0, input: 'abc fAbcdaBc cabc 123', groups: undefined]
    21. console.log(message1.match(regex1));
    22. // ['abc', index: 0, input: 'abc fAbcdaBc cabc 123', groups: undefined]
    23. console.log(message1.match(regex1));

            02 - matchAll

    一个在字符串中执行查找所有匹配的 String 方法,它返回一个迭代器(iterator)

     

    通俗的说 : 检测某一个字符串是否符合正则的规则,返回迭代器

    1. // 正则 => 匹配abc 全局查找,不区分大小写
    2. const regex = /abc/gi;
    3. // 字符串
    4. const message = 'abc fAbcdaBc cabc 123';
    5. /**
    6. * matchAll传入的正则修饰符必须加g,
    7. * 必须为全局查找,否则会报错
    8. */
    9. // 返回的是迭代器
    10. const res = message.matchAll(regex);
    11. // console.log(res.next()); // {value: Array(1), done: false}
    12. // console.log(res.next()); // {value: Array(1), done: false}
    13. // console.log(res.next()); // {value: Array(1), done: false}
    14. // console.log(res.next()); // {value: Array(1), done: false}
    15. // console.log(res.next()); // {value: undefined, done: true}
    16. // console.log(res.next()); // {value: undefined, done: true}
    17. // 迭代器可以使用for...of循环
    18. for (const iterator of res) {
    19. console.log(iterator);
    20. }
    21. /**
    22. * ['abc', index: 0, input: 'abc fAbcdaBc cabc 123', groups: undefined]
    23. * ['Abc', index: 5, input: 'abc fAbcdaBc cabc 123', groups: undefined]
    24. * ['aBc', index: 9, input: 'abc fAbcdaBc cabc 123', groups: undefined]
    25. * ['abc', index: 14, input: 'abc fAbcdaBc cabc 123', groups: undefined]
    26. */

            04 - replaceAll

    查找到对应的字符串,并且使用新的字符串进行替代

    1. // 字符串
    2. const message = 'abc fAbcdaBc cabc 123';
    3. // 必须全局查找,全部替换
    4. console.log(message.replaceAll(/abc/gi, 'star')); // star fstardstar cstar 123
    5. // 只替换第一个
    6. console.log(message.replace(/abc/i, 'star')); // star fAbcdaBc cabc 123
    7. // 替换全部
    8. console.log(message.replace(/abc/gi, 'star')); // star fstardstar cstar 123

    将字符串中数字全部删除 

    1. // 字符串
    2. const message = '1abc fAbcdaBc cabc 123';
    3. console.log(message.replaceAll(/\d+/gi, '')); // abc fAbcdaBc cabc

            05 - search

    一个在字符串中测试匹配的 String 方法,它返回匹配到的位置索引,或者在失败时返回-1

    1. // 正则
    2. const regex = /abc/gi;
    3. // 字符串
    4. const message = '1abc fAbcdaBc cabc 123';
    5. // 只会找到第一个出现的位置
    6. console.log(message.search(regex)); // 1

            06 - split

    一个使用正则表达式或者一个固定字符串分隔一个字符串,并将分隔后的子字符串存储到数组中的 String 方法

    1. // 正则
    2. const regex = /abc/i;
    3. // 字符串
    4. const message = '1abc fAbcdaBc cabc 123';
    5. // 切割,碰到abc切一刀 => 全局切
    6. console.log(message.split(regex)); // ['1', ' f', 'd', ' c', ' 123']

    二、修饰符的使用

    常见的修饰符 : 

    三、规则

    规则 – 字符类(Character classes)

    字符类(Character classes) 是一个特殊的符号,匹配特定集中的任何符号

    字符类

            01 - \d 

    1. const str = '123fff456aaa5423g 2432sd';
    2. const regex = /\d+/g;
    3. console.log(str.match(regex)); // ['123', '456', '5423', '2432']

            02 - \s 

    1. const str = '1\n23 fff\t\v456aa\fa5423g 2432s\vd';
    2. const regex = /\s+/g;
    3. console.log(str.match(regex)); // ['\n', ' ', '\t\v', '\f', ' ', '\v']

            03 - \w

    1. const str = '123 fff456aaa54 _23g_ 2432sd';
    2. const regex = /\w+/g;
    3. console.log(str.match(regex)); // ['123', 'fff456aaa54', '_23g_', '2432sd']

            04 - . 

    1. const str = '123 fff456aaa54 _23g_ 2432sd';
    2. const regex = /.+/g;
    3. // 全部匹配到
    4. console.log(str.match(regex)); // ['123 fff456aaa54 _23g_ 2432sd']

    反向类(Inverse classes)

    • \D 非数字:除 \d 以外的任何字符
    • \S 非空格符号:除 \s 以外的任何字符
    • \W 非单字字符:除 \w 以外的任何字符

    规则 – 锚点(Anchors)

    01 - ^ && $

    符号 ^ 和符号 $ 在正则表达式中具有特殊的意义,它们被称为“锚点”。


    符号 ^ : 匹配文本开头


    符号 $ : 匹配文本末尾

    1. const message = 'My name is stAr.';
    2. // 字符串方法
    3. console.log(message.startsWith('my')); // true
    4. console.log(message.endsWith('star')); // false
    5. // 已my开头
    6. console.log(/^my/i.test(message)); // true
    7. // 已star.开头
    8. console.log(/star\.$/i.test(message)); // true
    9. // 必须完全匹配coder
    10. const re = /^coder$/;
    11. const info = 'codaaaer';
    12. console.log(re.test(info)); // false

    02 - 词边界 \b

    词边界 \b 是一种检查,就像 ^ 和 $ 一样,它会检查字符串中的位置是否是词边界

    会去寻找字母

    1. // 需求: name, name必须是一个单独的词
    2. // 词边界
    3. console.log(/\bname\b/i.test('My name is stAr.')); // true
    4. console.log(/\bname\b/i.test('My namea is stAr.')); // false
    5. // 词边界的应用
    6. const infos = 'now time is 11:56, 12:00 eat food, number is 123:456';
    7. const timeRe = /\b\d\d:\d\d\b/gi;
    8. console.log(infos.match(timeRe)); // ['11:56', '12:00']
    1. const regex = /\b.+(tmall\.com|taobao\.com)(.+)*\b/gi;
    2. const str1 = '今天我掏到了宝贝https://detail.tmall.com/trest/94dcW?id=1234&a=4-g&b=6.4.3,冲冲冲';
    3. const str2 = '今天我掏到了宝贝,https://detail.taobao.com/trest/94d冲cWfd a冲冲冲';
    4. const str3 = '今天我掏到了宝贝,https://detail.baidu.com/trest/94dcWfd a冲冲冲';
    5. console.log(str1.match(regex)); // [ 'https://detail.tmall.com/trest/94dcW?id=1234&a=4-g&b=6.4.3' ]
    6. console.log(str2.match(regex)); // [ 'https://detail.taobao.com/trest/94d冲cWfd a' ]
    7. console.log(str3.match(regex)); // null

    规则 – 转义字符

    如果要把特殊字符作为常规字符来使用,需要对其进行转义 => 只需要在它前面加个反斜杠

    常见的需要转义的字符 : 

    • [] \ ^ $ . | ? * + ( )
    • 斜杠符号 ‘/’ 并不是一个特殊符号,但是在字面量正则表达式中也需要转义
    1. // 定义正则: 对.转义
    2. const re = /\./gi;
    3. const message = 'index.html';
    4. console.log(message.match(re)); // .

    匹配文件名 

    1. const fileNames = ['abc.html', 'Home.jsx', 'index.html', 'index.js', 'util.js', 'format.js'];
    2. const arr = fileNames.filter((item) => /\.jsx?$/.test(item));
    3. console.log(arr); // ['Home.jsx', 'index.js', 'util.js', 'format.js']

    规则 – 集合(Sets)和范围(Ranges)

    集合(Sets): 

    • 比如说,[eao] 意味着查找在 3 个字符 ‘a’、‘e’ 或者 `‘o’ 中的任意一个

    范围(Ranges): 

    • 方括号也可以包含字符范围
    • 比如说,[a-z] 会匹配从 a 到 z 范围内的字母,[0-5] 表示从 0 到 5 的数字
    • [0-9A-F] 表示两个范围:它搜索一个字符,满足数字 0 到 9 或字母 A 到 F
    • \d —— 和 [0-9] 相同
    • \w —— 和 [a-zA-Z0-9_] 相同

    匹配手机号码

    1. /**
    2. * 1 => 开头
    3. * 第二位 3-9的范围
    4. * 后面九位匹配数字
    5. * 然后结尾
    6. */
    7. const regex = /^1[3-9]\d{9}$/;
    8. console.log(regex.test('13423231234')); // true
    9. console.log(regex.test('a13423231234')); // false
    10. console.log(regex.test('13423231234a')); // false
    11. console.log(regex.test('12423231234')); // false

    排除范围

    除了普通的范围匹配,还有类似 [^…] 的“排除”范围匹配

    • [ ^0-9 ] : 表示匹配除了从 0 到 5 的数字
    • [ ^a-z ] : 表示匹配除了从 a 到 z 范围内的字母

    规则 – 量词(Quantifiers)

    用来形容我们所需要的数量的词被称为量词( Quantifiers )

    数量 {n}

    • 确切的位数:{5}
    • 某个范围的位数:{3,5} 

    缩写:

    • + :代表“一个或多个”,相当于 {1,}
    • ? :代表“零个或一个”,相当于 {0,1}。换句话说,它使得符号变得可选
    • * :代表着“零个或多个”,相当于 {0,}。也就是说,这个字符可以多次出现或不出现

    栗子一 🌰

    1. // 栗子
    2. const str = 'a b aa bb aaa bbb aaaa bbbb aaaaa bbbbb aaaaaa';
    3. console.log(str.match(/a{3}/gi)); // ['aaa', 'aaa', 'aaa', 'aaa', 'aaa'] 匹配的是后面几个大于3个的a
    4. console.log(str.match(/a{5,6}/gi)); // ['aaaaa', 'aaaaaa'] 匹配 5个a 或者 6个a

    栗子二 🌰

    1. // 栗子 🌰 => 匹配标签
    2. // 标签字符串
    3. const htmlElement = '
      哈哈哈

      我是标题

      '
      ;
    4. // 正则表达式
    5. const regex = /<\/?[a-z][0-9a-z]*>/gi;
    6. /**
    7. * / => 有或者没有
    8. * 第一个肯定是字母 => [a-z]
    9. * 第二个可能是字母可能是数字,也可能没有 => [0-9a-z]*
    10. * gi => 全局搜索,忽略大小写
    11. */
    12. const res = htmlElement.match(regex);
    13. console.log(res); // ['
      ', '', '', '', '', '

      ', '

      ', '
      ']

    规则 – 贪婪( Greedy)和惰性( lazy)模式

    需求:匹配下面字符串中所有使用《》包裹的内容

    贪婪模式 : 

    默认情况下的匹配规则是查找到匹配的内容后,会继续向后查找,一直找到最后一个匹配的内容

    1. const message = '我最喜欢的两本书: 《黄金时代》和《沉默的大多数》、《一只特立独行的猪》';
    2. const regex = /《.+》/gi;
    3. // 贪婪模式 : 没有分开,从最开始的《一直匹配到最后一个》
    4. console.log(message.match(regex)); //['《黄金时代》和《沉默的大多数》、《一只特立独行的猪》']

    惰性模式 : 

    懒惰模式中的量词与贪婪模式中的是相反的

    • 只要获取到对应的内容后,就不再继续向后匹配
    • 可以在量词后面再加一个问号 ‘?’ 来启用它
    • 所以匹配模式变为 *? 或 +?,甚至将 '?' 变为 ?? 
    1. const message = '我最喜欢的两本书: 《黄金时代》和《沉默的大多数》、《一只特立独行的猪》';
    2. const regex = /《.+?》/gi;
    3. // 在量词后加一个 ? 号,开启惰性模式
    4. console.log(message.match(regex)); // ['《黄金时代》', '《沉默的大多数》', '《一只特立独行的猪》']

    规则 – 捕获组(capturing group)

    捕获组

    捕获组 : 模式的一部分可以用括号括起来 (...),这称为“捕获组(capturing group)

    这有两个作用:

    • 它允许将匹配的一部分作为结果数组中的单独项
    • 它将括号视为一个整体

    方法 str.matchAll(regexp),返回迭代器对象后,遍历的结果 : 

    • 在索引 0 处:完全匹配。
    • 在索引 1 处:第一个括号的内容。
    • 在索引 2 处:第二个括号的内容
    1. const message = '我最喜欢的两本书: 《黄金时代》和《沉默的大多数》、《一只特立独行的猪》';
    2. /**
    3. * 括号用来分组
    4. * 这里分成了三个组
    5. */
    6. const regex = /(《)(.+?)(》)/gi;
    7. const res = message.matchAll(regex);
    8. for (const iterator of res) {
    9. console.log(iterator);
    10. }
    11. /**
    12. * 0: "《黄金时代》" // 总的匹配结果
    13. 1: "《" // 第一个组
    14. 2: "黄金时代" // 第二个组
    15. 3: "》" // 第三个组
    16. groups: undefined
    17. index: 10
    18. input: "我最喜欢的两本书: 《黄金时代》和《沉默的大多数》、《一只特立独行的猪》"
    19. */

    命名组 

    • 用数字记录组很困难
    • 对于更复杂的模式,计算括号很不方便。有一个更好的选择:给括号起个名字
    • 这是通过在开始括号之后立即放置 ? 来完成的
    1. const message = '我最喜欢的两本书: 《黄金时代》和《沉默的大多数》、《一只特立独行的猪》';
    2. /**
    3. * 括号用来分组
    4. * 这里分成了三个组
    5. * 给三个组取了名字
    6. */
    7. const regex = /(?《)(?.+?)(?》)/gi;
    8. const res = message.matchAll(regex);
    9. for (const iterator of res) {
    10. console.log(iterator);
    11. console.log(iterator.groups.content); // '黄金时代'
    12. }
    13. /**
    14. * 0: "《黄金时代》"
    15. 1: "《"
    16. 2: "黄金时代"
    17. 3: "》"
    18. groups: {firstIcon: '《', content: '黄金时代', lastIcon: '》'}
    19. index: 10
    20. input: "我最喜欢的两本书: 《黄金时代》和《沉默的大多数》、《一只特立独行的猪》"

    非捕获组

    • 有时我们需要括号才能正确应用量词,但我们不希望它们的内容出现在结果中。
    • 可以通过在开头添加 ?: 来排除组
    1. const message = '我最喜欢的两本书: 《黄金时代》和《沉默的大多数》、《一只特立独行的猪》';
    2. /**
    3. * 括号用来分组
    4. * 这里分成了三个组
    5. * 但是忽略了第一个组和第三个组
    6. */
    7. const regex = /(?:《)(?.+?)(?:》)/gi;
    8. const res = message.matchAll(regex);
    9. for (const iterator of res) {
    10. console.log(iterator);
    11. console.log(iterator.groups.content); // '黄金时代'
    12. }
    13. /**
    14. * 0: "《黄金时代》"
    15. 1: "黄金时代"
    16. groups: {content: '黄金时代'}
    17. index: 10
    18. input: "我最喜欢的两本书: 《黄金时代》和《沉默的大多数》、《一只特立独行的猪》"
    19. */

    或 or

    1. // 正则 => 匹配规则,是否以.()这些结尾
    2. const reg = /\.(AMR|WAV|AWB|mp3|mp4)$/;
    3. // 字符串
    4. const str1 = 'abc.mp3';
    5. const str2 = 'abc.mp4';
    6. const str3 = 'abc.WAV';
    7. const str4 = 'abc.mp6';
    8. console.log(reg.test(str1)); // true
    9. console.log(reg.test(str2)); // true
    10. console.log(reg.test(str3)); // true
    11. console.log(reg.test(str4)); // false

    四、常用正则

    1. 去除字符串空格

    首部          :  str.replace( /^\s+/ , '' ) 

    尾部          :  str.replace( /\s+$/ , '' )  

    首尾部      :  str.replace(/\s+$/g , '' ) 

    全部          :  str.replace(/\s/g , '' ) 

    1. // 测试数组
    2. const arr = [' adf', ' a d b ', ' a '];
    3. const newArr = arr.map((item) => {
    4. // 1. 字符串自带方法
    5. // return item.trim();
    6. // 2. 先去除首部,再去除尾部
    7. // return item.replace(/^\s+/, '').replace(/\s+$/, '');
    8. // 3. 去除首尾部
    9. return item.replace(/^\s+|\s+$/g, '');
    10. });
    11. console.log(newArr); // ['adf', 'a d b', 'a']

    2. 匹配手机号

    匹配  :  regex = /^1[3-9]\d{9}$/

    1. /**
    2. * 1 => 开头
    3. * 第二位 3-9的范围
    4. * 后面九位匹配数字
    5. * 然后结尾
    6. */
    7. const regex = /^1[3-9]\d{9}$/;
    8. console.log(regex.test('13423231234')); // true
    9. console.log(regex.test('a13423231234')); // false
    10. console.log(regex.test('13423231234a')); // false
    11. console.log(regex.test('12423231234')); // false

    3. 歌词解析

    匹配  :  regex = /

    (?<m>\d2):(?<s>\d2)\.(?<ms>\d2,3)" role="presentation" style="text-align: center; position: relative;">(?<m>\d2):(?<s>\d2)\.(?<ms>\d2,3)
    /

    1. // 歌词字符串
    2. const lyricsStr =
    3. '[00:00.000] 作词 : 许嵩\n[00:01.000] 作曲 : 许嵩\n[00:02.000] 编曲 : 许嵩\n[00:22.240]天空好想下雨\n[00:24.380]我好想住你隔壁\n[00:26.810]傻站在你家楼下\n[00:29.500]抬起头数乌云\n[00:31.160]如果场景里出现一架钢琴\n[00:33.640]我会唱歌给你听\n[00:35.900]哪怕好多盆水往下淋\n[00:41.060]夏天快要过去\n[00:43.340]请你少买冰淇淋\n[00:45.680]天凉就别穿短裙\n[00:47.830]别再那么淘气\n[00:50.060]如果有时不那么开心\n[00:52.470]我愿意将格洛米借给你\n[00:55.020]你其实明白我心意\n[00:58.290]为你唱这首歌没有什么风格\n[01:02.976]它仅仅代表着我想给你快乐\n[01:07.840]为你解冻冰河为你做一只扑火的飞蛾\n[01:12.998]没有什么事情是不值得\n[01:17.489]为你唱这首歌没有什么风格\n[01:21.998]它仅仅代表着我希望你快乐\n[01:26.688]为你辗转反侧为你放弃世界有何不可\n[01:32.328]夏末秋凉里带一点温热有换季的颜色\n[01:41.040]\n[01:57.908]天空好想下雨\n[01:59.378]我好想住你隔壁\n[02:02.296]傻站在你家楼下\n[02:03.846]抬起头数乌云\n[02:06.183]如果场景里出现一架钢琴\n[02:08.875]我会唱歌给你听\n[02:10.974]哪怕好多盆水往下淋\n[02:15.325]夏天快要过去\n[02:18.345]请你少买冰淇淋\n[02:21.484]天凉就别穿短裙\n[02:22.914]别再那么淘气\n[02:25.185]如果有时不那么开心\n[02:27.625]我愿意将格洛米借给你\n[02:30.015]你其实明白我心意\n[02:33.327]为你唱这首歌没有什么风格\n[02:37.976]它仅仅代表着我想给你快乐\n[02:42.835]为你解冻冰河为你做一只扑火的飞蛾\n[02:48.406]没有什么事情是不值得\n[02:52.416]为你唱这首歌没有什么风格\n[02:57.077]它仅仅代表着我希望你快乐\n[03:01.993]为你辗转反侧为你放弃世界有何不可\n[03:07.494]夏末秋凉里带一点温热\n[03:11.536]\n[03:20.924]为你解冻冰河为你做一只扑火的飞蛾\n[03:26.615]没有什么事情是不值得\n[03:30.525]为你唱这首歌没有什么风格\n[03:35.196]它仅仅代表着我希望你快乐\n[03:39.946]为你辗转反侧为你放弃世界有何不可\n[03:45.644]夏末秋凉里带一点温热有换季的颜色\n';
    4. // 切割歌词
    5. const lyricsSplit = lyricsStr.split('\n');
    6. // 正则,匹配时间
    7. const regex = /\[(?\d{2}):(?\d{2})\.(?\d{2,3})\]/;
    8. // 解析后的歌词数组
    9. const lyricsInfos = [];
    10. for (const lyrics of lyricsSplit) {
    11. // 拿到整体时间
    12. const res = lyrics.match(regex);
    13. if (!res) continue;
    14. // 拿到分钟,转换为毫秒
    15. const m = res[1] * 60 * 1000;
    16. // 拿到秒钟,转换为毫秒
    17. const s = res[2] * 1000;
    18. // 拿到毫秒, 可能是2位数,可能是3位数
    19. const ms = res[3].length === 3 ? res[3] * 1 : res[3] * 10;
    20. const time = m + s + ms;
    21. // 拿到内容
    22. const content = lyrics.replace(regex, '').trim();
    23. lyricsInfos.push({
    24. time,
    25. content
    26. });
    27. }
    28. console.log(lyricsInfos); // [{time: 0, content: '作词 : 许嵩'} , ... , ...]

    4. 时间格式化

    时间戳 1659252290626​​​​​​​  =>  变为 2022-10-02 12:34:45

    1. // timestamp: 1659252290626
    2. // yyyy/MM/dd hh:mm:ss
    3. // yyyy*MM*dd hh-mm-ss
    4. function formatTime(timestamp, fmtString) {
    5. // 1. 获取时间对象
    6. const data = new Date(timestamp); // Wed Aug 24 2022 14:44:36 GMT+0800 (中国标准时间)
    7. // 2. 时间转换
    8. const dataO = {
    9. // 匹配 yyyy => 年份
    10. 'y+': data.getFullYear(),
    11. // 匹配 MM => 月份
    12. 'M+': data.getMonth() + 1,
    13. // 匹配 dd => 日
    14. 'd+': data.getDate(),
    15. // 匹配 hh => 时
    16. 'h+': data.getHours(),
    17. // 匹配 mm => 分
    18. 'm+': data.getMinutes(),
    19. // 匹配 ss => 秒
    20. 's+': data.getSeconds()
    21. };
    22. for (const key in dataO) {
    23. // 拿到对应的正则字符串
    24. const timeRegex = new RegExp(key, 'g');
    25. // 看是否需要匹配
    26. if (timeRegex.test(fmtString)) {
    27. // 小于两位数的,用 0 在前方补齐
    28. const value = ('' + dataO[key]).padStart(2, '0');
    29. // 把匹配到的位置用数值来替换
    30. fmtString = fmtString.replace(timeRegex, value);
    31. }
    32. }
    33. return fmtString;
    34. }
    35. formatTime(new Date().getTime(), 'yyyy-MM-dd hh:mm:ss'); // 2022-08-24 15:18:33
    36. formatTime(new Date().getTime(), 'yyyy/MM/dd hh-mm-ss'); // 2022/08/24 15-18-33
    37. formatTime(new Date().getTime(), 'yyyy MM dd hh:mm:ss'); // 2022 08 24 15:18:33
    38. formatTime(new Date().getTime(), 'hh:mm:ss yyyy-MM-dd '); // 15:18:33 2022-08-24

  • 相关阅读:
    科研工具分享-SCI写作课
    【HTML5期末大作业】制作一个简单HTML我的班级网页(HTML+CSS+JS)
    分布式代理IP的优势及用途有哪些?
    使用 Dockerfile 定制镜像
    使用百度的长文本转语音API时无法下载.MP3文件
    遥感云大数据在灾害、水体与湿地领域及GPT模型应用
    买房怎样申请贷款
    【单片机原理及应用】第一篇——单片机概述
    从0搭建Azure DevOps Server
    RocketMQ 基于时间轮算法实现指定时间点的定时消息原理解析
  • 原文地址:https://blog.csdn.net/a15297701931/article/details/126479577