跳到主要内容

学习字符串利器---正则

阅读需 6 分钟
正则大芒果

/\$(\$)?([^]*?)\$(\$)?/

匹配单$$数学公式内容然后进行渲染

分割符号

/(<[^>]+>|\$\$.+?\$\$|\$.+?\$|&[a-zA-Z]{2,8};)/gim

  • <[^>]+> :匹配HTML或者XML标签
  • \$\$.+?\$\$ : 匹配类似Latex语法,+?是非贪婪匹配,尽可能少
  • \$.+?\$ : 同上,双美元是块渲染,单美元是行内渲染
  • &[a-zA-Z]{2,8}; :匹配HTML实体,类似&amp;
  • | :是支持多种模式
  • /gim : 多次匹配,多行模式,大小写不敏感

正则表达式

创建方式主要两种

  • RegExp regexp = new RegExp('patten','flags)
  • 字面量 /abc/g

修饰符

常见

  • g : 返回全部匹配项
  • i : 大小写不敏感
  • u : 开启unicode字符支持
  • s: 开始点完全匹配模式
  • m: 开启锚点多行模式

方法

搜索

字符串.match(正则表达式)

返回匹配的字符数组

没有/g的话,还有.index .input等额外方法

没有匹配项返回null

替换

字符串.replace(正则表达式,replacement)

// 没有修饰符 g
alert( "We will, we will".replace(/we/i, "I") ); // I will, we will

// 带有修饰符 g
alert( "We will, we will".replace(/we/ig, "I") ); // I will, I will

replacement参数

符号在替换字符串中的行为
$&插入整个匹配项
`$``插入字符串中匹配项之前的字符串部分
$'插入字符串中匹配项之后的字符串部分
$n如果 n 是一个 1-2 位的数字,则插入第 n 个分组的内容,详见 捕获组
$<name>插入带有给定 name 的括号内的内容,详见 捕获组
$$插入字符 $
测试

字符串.test(正则表达式)

至少有一个就返回true,否则返回false

字符类

\d digit, 0-9

\s space,类似\n,\t这种

\w word, 字母,数字,下拉线_

反向类

\D 除数字的字符都行

\S 同上

\W 同上

点(.)匹配”所有字符“

. 是一种特殊字符类,它与“除换行符之外的任何字符”匹配。

例如:

alert('Z'.match(/./)) // Z

带有修饰符 “s” 时点字符类匹配任何字符

alert('A\nB'.match(/A.B/s)) // A\nB(匹配了!)
锚点:字符串开始 ^ 和末尾 $

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

插入符号 ^ 匹配文本开头,而美元符号 $ 则匹配文本末尾。

结合起来,就是可以实现完美匹配

多行模式 修饰符m

加上了就可以匹配多行开头,多行结尾了

词边界

\b

有三种不同的位置可作为词边界:

  • 在字符串开头,如果第一个字符是单词字符 \w
  • 在字符串中的两个字符之间,其中一个是单词字符 \w,另一个不是。
  • 在字符串末尾,如果最后一个字符是单词字符 \w

集合与范围[...]

集合

在方括号 […] 中的几个字符或者字符类表示“搜索给定字符中的任意一个”。

[QWER]表示以下 4个字符中的任何一个:'Q''W''E''R'

范围

方括号也可以包含 字符范围

例如,[a-z] 表示从 az 范围内的字符,[0-5] 表示从 05 的数字

[0-9A-F] 中有两个范围:

它搜索一个字符,该字符要么是在 09 范围内的数字,要么是从 AF 的字母。

排除范围

除了普通的范围匹配,还有像这样 [^…] 的“排除”范围匹配。

通过在开头添加插入符号 ^ 来表示匹配所有 除了给定的字符 之外的任意字符。

  • [^aeyo] —— 匹配除了 'a''e''y''o' 之外的任何字符。
  • [^0-9] —— 匹配除了数字之外的任何字符,与 \D 作用相同。
  • [^\s] —— 匹配任何非空格字符,与 \S 作用相同。
[…] 中的转义

通常当我们想要准确地找到一个特殊字符时,我们需要像 \. 这样对其进行转义。如果我们需要反斜杠,那么我们需要使用 \\,等等。

在方括号,我们可以使用绝大多数特殊字符而无需转义:

  • 符号 . + ( ) 无需转义。
  • 在开头或结尾(未定义范围)的连字符 - 不会被转义。
  • 插入符号 ^ 仅在开头会被转义(表示排除)。
  • 右方括号 ] 总是会被转义(如果我们需要寻找那个符号)。
范围和修饰符 “u”

如果集合中有代理对(surrogate pairs),则需要标志 u 才能使它们正常工作。

例如,让我们在字符串 𝒳 中查找 [𝒳𝒴]

  • 量词(Quantifiers){n}+?*

    {n}

    确切的位数
    {5}` => `\d{5}` === `\d\d\d\d\d
    范围

    {3,5} 匹配 3-5 个

    {,5} 匹配最多 5 个

    {6,} 匹配至少 6 个

    量词缩写

    • + : 一个及以上,=== {1,}
    • \* : 零个及以上,=== {0,}
    • ? : 零个或一个,=== {0,1}

贪婪量词与惰性量词

看一个样例先

let regexp = /".+"/g

let str = 'a "witch" and her "broom" is one'

alert(str.match(regexp)) // "witch" and her "broom"

……可以看出来它的运行结果与我们的预期不同!

在贪婪模式下(默认情况),量词都会尽可能多地重复。

惰性量词(Lazy Quantifiers)

在默认情况下,量词是“贪婪的”,这意味着它们会尽可能多地匹配字符。通过在量词后面加上 ?,可以将其变为“惰性的”,即尽可能少地匹配字符。

  • *? : 零个或多个,尽可能少
  • +? : 一个或多个,尽可能少
  • ?? : 零个或一个,尽可能少
  • {n,m}? : n 到 m 个,尽可能少
  • {n,}? : 至少 n 个,尽可能少

示例

假设我们有以下字符串:"aaaaa"

  1. 贪婪匹配(Greedy Matching)

    模式:a+

    匹配结果:["aaaaa"]

  2. 惰性匹配(Lazy Matching)

    模式:a+?

    匹配结果:["a", "a", "a", "a", "a"]

捕获组

(...)称为“捕获组(capturing group)”。

  • 它允许将匹配的一部分作为结果数组中的单独项。
  • 如果我们将量词放在括号后,则它将括号视为一个整体。

命名组

在左括号后紧跟着放置 ?\<name\> 即可完成对括号的命名。

例如,让我们查找 “year-month-day” 格式的日期:

let dateRegexp = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/;
let str = "2024-06-18";

let groups = str.match(dateRegexp).groups;

alert(groups.year); // 2024
alert(groups.month); // 06
alert(groups.day); // 18

替换中的捕获组

let str = "John Bull";
let regexp = /(\w+) (\w+)/;

alert( str.replace(regexp, '$2, $1') ); // Bull, John

对于命名的括号,引用为 $<name>

非捕获组 ?:

有点抽象,回去多试试

有时我们需要用括号才能正确应用量词,但我们不希望它们的内容出现在结果中

::: notice

像搭积木一样,材料越多也越来复杂

:::

模式中的反向引用:\N 和 \k<name>

引入一个任务,我们想要匹配这两种'...'"..."

如果使用的模版是['"](.*?)['"],则会有下面的问题

let str = `He said: "She's the one!".`

let regexp = /['"](.*?)['"]/g

// 不是我们想要的结果
alert(str.match(regexp)) // "She'

抓虫

{n}导致了mdx文件崩溃,因为是一个变量

Loading Comments...