【JavaScript】常用正则表达式 +歌词解析 + 时间格式化

21 篇文章 0 订阅
20 篇文章 1 订阅

❓ 什么是正则表达式?

我们先来看一下维基百科对正则表达式的解释:
✅ 正则表达式(英语:Regular Expression,常简写为regex、regexp或RE),又称正则表示式、正则表示法、规则表达式、常规表示法,是计算机科学的一个概念;

  • 正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。
  • 许多程序设计语言都支持利用正则表达式进行字符串操作。

简单概况:正则表达式是一种字符串匹配利器,可以帮助我们搜索、获取、替代字符串;
在JavaScript中,正则表达式使用RegExp类来创建,也有对应的字面量的方式:
正则表达式主要由两部分组成:模式(patterns)和修饰符(flags)。

const reg1 = new RegExp('aaaa', 'i');
const reg2 = /aaaa/i;

正则表达式的使用方法

❓ 有了正则表达式我们要如何使用它呢?

✅ JavaScript中的正则表达式被用于 RegExp 的 exec 和 test 方法;
✅ 也包括 String 的 match、matchAll、replace、search 和 split 方法;

方法描述
exec一个在字符串中执行查找匹配的 RegExp 方法,它返回一个数组(未匹配到则返回 null)。
test一个在字符串中测试是否匹配的 RegExp 方法,它返回 true 或 false。
match一个在字符串中执行查找匹配的 String 方法,它返回一个数组,在未匹配到时会返回 null。
matchAll一个在字符串中执行查找所有匹配的 String 方法,它返回一个迭代器(iterator)。
search一个在字符串中测试匹配的 String 方法,它返回匹配到的位置索引,或者在失败时返回-1。
replace一个在字符串中执行查找匹配的 String 方法,并且使用替换字符串替换掉匹配到的子字符串。
split一个使用正则表达式或者一个固定字符串分隔一个字符串,并将分隔后的子字符串存储到数组中 的 String 方法。

修饰符flag的使用

常见的修饰符:

flag含义
g全部的,给我匹配全部的(global)
i忽略大小写(ignore)
m多行匹配(multiple)

❗ 需求: 1️⃣ 获取一个字符串中所有的abc;2️⃣ 将一个字符串中的所有abc换成大写;

let message = "Hello ABC,abc,Abc,AAaBC";
const pattern = /abc/ig;
const result = message.match(pattern);
console.log(result);

message = message.replaceAll(pattern, 'ABC');
console.log(message)

在这里插入图片描述

规则 – 字符类(Character classes)

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

字符含义
\d (“d"来自"digit”)数字:从0到9的字符。
\s (“s"来自"space”)空格字符:包括空格,制表符 \t,换行符 \n 和其他少数稀有字符,例如\v \f \r。
\w (“w"来自"word”)“单字”字符:拉丁字母或数字或下划线 _ 。
. (点)点 . 是一种特殊字符类,它与“除换行符之外的任何字符”匹配

反向类 (Inverse classes)

  • \D 非数字:除 \d 以外的任何字符,例如字母。
  • \S 非空格符号:除 \s 以外的任何字符,例如字母。
  • \W 非单字字符:除 \w 以外的任何字符,例如非拉丁字母或空格。

规则 – 锚点(Anchors)

符号 ^ 和符号 $ 在正则表达式中具有特殊的意义,它们被称为“锚点”。
✅ 符号 ^ 匹配文本开头;
✅ 符号 $ 匹配文本末尾;
词边界(Word boundary)
词边界 \b 是一种检查,就像 ^ 和 $ 一样,它会检查字符串中的位置是否是词边界。
词边界测试 \b 检查位置的一侧是否匹配 \w,而另一侧则不匹配 “\w”
在字符串 Hello, Java! 中,以下位置对应于 \b:

规则 – 转义字符

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

✅ 常见的需要转义的字符:
[] \ ^ $ . | ? * + ( )

斜杠符号 ‘/’ 并不是一个特殊符号,但是在字面量正则表达式中也需要转义;

练习:匹配所有以.js或者jsx结尾的文件名

const fileNames = ["abc.js", "cba.java", "nba.html", "mba.js", "aaa.jsx"];
let reg = /\.jsx?$/;
const newNames = fileNames.filter((item) => {
  return reg.test(item)
})
console.log(newNames);

在webpack当中,匹配文件名时就是以这样的方式。

集合(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_] 相同;

案例:匹配手机号码
const phonePattern = /^1[356789]\d{9}$/

◼ 排除范围:除了普通的范围匹配,还有类似 [^…] 的“排除”范围匹配;
[^0-9]:排除数字0-9的范围

量词(Quantifiers)

◼ 假设我们有一个字符串 +7(903)-123-45-67,并且想要找到它包含的所有数字。

  • 因为它们的数量是不同的,所以我们需要给与数量一个范围;
  • 用来形容我们所需要的数量的词被称为量词( Quantifiers )

数量 {n}

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

缩写:

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

**案例:匹配开始或结束标签 **

const htmlElement = "<div><p>哈哈哈哈</p><span>heihei</span><h2>h2</h2></span></div>";
const tagPatter = /<\/?[a-z][a-z0-9]*>/ig;
console.log(htmlElement.match(tagPatter))

贪婪( Greedy)和惰性( lazy)模式

  • 如果我们有这样一个需求:匹配下面字符串中所有使用《》包裹的内容

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

    • 这种匹配的方式,我们称之为贪婪模式(Greedy)
  • 懒惰模式中的量词与贪婪模式中的是相反的。

    • 只要获取到对应的内容后,就不再继续向后匹配;
    • 我们可以在量词后面再加一个问号 ‘?’ 来启用它;
    • 所以匹配模式变为 *? 或 +?,甚至将 ‘?’ 变为 ??
const message = "我最喜欢的两本书:《家》、《春秋》";
// 默认 .+ 采用贪婪模式
// const reg = /《.+》/ig;
// 使用懒惰模式
const reg = /《.+?》/ig;
const result = message.match(reg);
console.log(result)

在这里插入图片描述
在这里插入图片描述

捕获组(capturing group)

模式的一部分可以用括号括起来 (…),这称为“捕获组(capturing group)”。
◼ 这有两个作用:

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

方法 str.match(regexp),如果 regexp 没有 g 标志,将查找第一个匹配并将它作为一个数组返回:

  • 在索引 0 处:完全匹配。
  • 在索引 1 处:第一个括号的内容。
  • 在索引 2 处:第二个括号的内容。

 …等等…

案例:匹配到《》,并且获取其中的内容

const message = "我最喜欢的两本书:《家》、《春秋》、《黄金时代》";

const reg = /《(.+?)》/ig;
const resultIteraor = message.matchAll(reg);
for (const item of resultIteraor) {
  console.log(item[1])
}

在这里插入图片描述

捕获组的补充

命名组:

  • 用数字记录组很困难。
  • 对于更复杂的模式,计算括号很不方便。
  • 我们有一个更好的选择:给括号起个名字。 这是通过在开始括号之后立即放置 ? 来完成的。

非捕获组:

  • 有时我们需要括号才能正确应用量词,但我们不希望它们的内容出现在结果中。
  • 可以通过在开头添加 ?: 来排除组。

or是正则表达式中的一个术语,实际上是一个简单的“或”。

  • 在正则表达式中,它用竖线 | 表示;
  • 通常会和捕获组一起来使用,在其中表示多个值;

案例: 歌词解析

// 解析歌词
// http://123.207.32.32:9002/lyric?id=167876
const lyricString = "[00:00.000] 作词 : 许嵩\n[00:01.000] 作曲 : 许嵩\n[00:02.000] 编曲 : 许嵩\n[00:03.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";


const lyricArr = [];


const lyricStringsArr = lyricString.split('\n');
const lyricTimeRe = /\[(\d{2}):(\d{2})\.(\d{2,3})\]/;


for (const item of lyricStringsArr) {
  const timeArr = item.match(lyricTimeRe);
  if (!timeArr) continue
  const min = timeArr[1] * 60 * 1000;
  const second = timeArr[2] * 1000;
  const minSecond = timeArr[3].length === 3 ? timeArr[3] * 1 : timeArr[3] * 10;
  const time = min + second + minSecond


  const lyricContent = item.replace(lyricTimeRe, "").trim();


  lyricArr.push({ time, lyricContent })
}


console.log(lyricArr);

在这里插入图片描述

案例:格式化时间

时间格式化:从服务器拿到时间戳,转成想要的时间格式

// 时间格式化
//  时间格式化:从服务器拿到时间戳,转成想要的时间格式


function formatDate(time, timeFormat) {
  const date = new Date(time);
  console.log(date);
  const week = ["日", "一", "二", "三", "四", "五", "六"];
  const regObj = {
    "y+": date.getFullYear(),
    "M+": date.getMonth() + 1,
    "d+": date.getDay(),
    "h+": date.getHours(),
    "m+": date.getMinutes(),
    "s+": date.getSeconds(),
    "w": week[date.getDay()]
  }
  for (const key in regObj) {
    const keyReg = new RegExp(key, 'i');
    if (keyReg.test(timeFormat)) {
      // const value = (regObj[key] + "").padStart(2, "0");
      let value = regObj[key];
      if (typeof (value) === 'number') {
        value = (value + "").padStart(2, "0")
      }
      timeFormat = timeFormat.replace(keyReg, value)
    }
  }


  return timeFormat
}



const obj = {
  name: 'lllll',
  time: Date.now()
}

const time = obj.time;
let result = formatDate(time, 'yyyy年MM月dd日 h:mm:ss 星期w');
console.log(result);


// console.log(formatDate(new Date(1409894060000), 'yyyy-MM-dd HH:mm:ss 星期w'))

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

起伏羊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值