参考资料

这个教程,真的让我学会了正则表达式 - 知乎 (zhihu.com)

Regular Expressions for Regular Folk | Regular Expressions for Regular Folk (REFRF)

Regexper 正则表达式图形解析

[RegExr: Learn, Build, & Test RegEx 解析](https://regexr.com/?expression=%2Fp%2Fgm&text=pancake pineapple apple mango Plum)

状态消除算法可将任意的有穷状态机转为正则表达式

基本概念

正则表达式的标准格式为/<rules>/<flags>,其中,flags一般会省略,默认情况下flag为g.

在默认情况下,正则表达式是大小写敏感的。

在待匹配的字符串中,与给定正则表达式匹配的内容称作”matches”

单个字符匹配

使用序列字符匹配同样的字符序列

如:/p/g

可以匹配给定字符串中的每一个p

又如:/jeck/g

则可以匹配给定字符串中的每一个jeck

字符匹配集

列举法

允许使用一个可选的字符集合去匹配单个字符。语法格式为[]

例如:/p[aeiou]t/g

可以匹配如patpet……等所有方括号中出现的字符且只出现了一次与两侧的p和t组成的内容。

范围写法

允许使用-字符表示一个范围

例如:[a-z0-9A-Z]可匹配012…89ab..zA…Z中的每一个字符,但也只能匹配单个字符。

取反匹配集

使用^字符作用于字符匹配集,达到匹配除字符匹配集中字符外任一字符的效果

例如:[^a-z0-9A-Z]则可以匹配任意非【012…89ab..zA…Z】中的字符(单个),任一字符只要不是这些字符中的一个就能被匹配到。

转义字符

在正则表达式中的转义字符有两种意义,其一是常见的将正则表达式中具有语法意义的特殊字符进行转义从而表示其对应的普通字符,其二则是表示一些默认的字符集

默认字符集

  • \d表示所有的数字,相当于[0-9]
  • \D相当于^[0-9]
  • \w相当于[a-zA-Z0-9_]
  • \W相当于[^a-zA-Z0-9_]
  • \s表示所有的空字符,具体实现看引擎,通常包括
    • 空格
    • tab\t
    • 回车\r
    • 换行\n
    • 换页\f
    • 垂直制表符\v
  • \S以上取反
  • .表示任意非\n字符,不过可以通过添加flag:dotAll来使其匹配换行符

语法字符(escape)

列出正则表达式中具有特殊意义的语法字符:

  • |
  • {}
  • ()
  • []
  • ^
  • $
  • +,*,?
  • \
  • .,但在字符集中可以直接表示dot字符
  • -,仅在字符集中有特殊含义

表达式中元素的分组,有以下作用

  • 提取匹配的子集
  • 以组为单位重复
  • 引用先前匹配到的组
  • 增强可读性
  • 允许复杂的替换动作

捕获组

使用圆括号进行捕获组的标识

如:/a(bcd)e/g

可以匹配abcde,同时bcd会为其中的一个捕获组

在使用编程语言所提供的正则表达式方法时,可以使用提供的api提取出其中的捕获组部分。

以组为单位重复

如:/a(bcd)+e/g

其中bcd可以整体作为重复单元被后面的+标识

提高可读性

/(\d\d\d\d)-W(\d\d)/g

其中并没有使用到组的语法特性,只是为了提高表达式可读性

引用

被捕获组捕获的内容可以在后面被引用,注意是捕获的内容,而不是捕获组的相同规则。引用方式为\1,其中1为捕获组的索引

如:/([abc])=\1=\1/g

可以匹配a=a=a,但是不能匹配a=b=c,因为捕获组捕获到的第一个内容是a,所以后面引用时也需要是a,注意:捕获组引用与如下表达式的效果不同:/[abc][abc][abc]/g,这个表达式是可以匹配到a=b=c

引用不能在字符集中使用

非捕获组

非捕获组用于在不需要后续引用,但当前又要以组单位重复,此时可以使用非捕获组,格式为(?:...)

如:/^\?(\w+)=(\w+)(?:&(\w+)=(\w+))*$/g

后面那个就是非捕获组,用于将整体作为重复单元

非捕获组可以提高性能,避免不必要的捕获组存储

替换

在一些具有替换功能的正则引擎中,可以通过$1的方式获取捕获组的内容(1为捕获组索引)并用于替换,如:

1
2
3
4
5
6
7
8
9
10
11
Find: \b(\w+) (\w+)\b

Replace: $2, $1

Before
John Doe
Jane Doe

After
Doe, John
Doe, Jane

又如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Find: \bword(s?)\b

Replace: phrase$1
=======================
Before
This is a paragraph with some words.

Some instances of the word "word" are in their plural form: "words".

Yet, some are in their singular form: "word".
======================
After
This is a paragraph with some phrases.

Some instances of the phrase "phrase" are in their plural form: "phrases".

Yet, some are in their singular form: "phrase".

image-20240816113506595

重复

重复修饰符用于重复字符或组

重复字符有:

  • ?:0次或1次重复
  • *:0次或多次重复
  • +:1次或多次重复
  • {n}:指定n次重复
  • {m,n}:最少m次重复,最多n次重复,注意逗号后面没有空格
  • {m,}:最少m次重复,上不封顶

贪婪模式与非贪婪模式

默认情况下,重复匹配都是贪婪的,既会一直匹配到后面的内容不满足为止:

比如:/a{2,4}/g,如果存在4个a连在一起的情况,则会优先匹配aaaa,而如果将表达式改为/a{2,4}?/g,则当匹配到两个a的情况时即会认为是一个匹配,此时为非贪婪模式,又叫懒匹配

如:/".*"/g会将"123","456"整个匹配,因为字符串的两端都是引号,但:/".*"?/g则会将其中的”123”和”456”分别匹配(此处需求最合适的表达式是 /"[^"]*"/g

非贪婪模式会在当前条件已经满足的时候停止,而非贪婪模式则会在后面的条件不满足时停止

交替(词集)

词集可用于在词的集合中匹配,类似于字符集但以词为最小单位

语法:apple|peer|banana

可以匹配这三个词中的任意一个

使用时建议使用组将词集包裹,否则会匹配其他部分如:

/Try app|bana/g会匹配Try app或者bana

而:/Try (app|bana)/g则会匹配Try app或者Try bana

词集是从左到右匹配的,若左边已经有匹配到的内容,则不会考虑后面的词规则

flag

flag会让正则表达式处在不同的模式下解析,多个flag可同时生效

  • g global

    global生效时,会取出字符串中每一处生效的内容,如果不加g,则只会匹配一次。

  • i insensitive

    i生效后,匹配时,英文将会大小写不敏感

  • m multiline

    多行模式,会将每一行单独作为匹配源,默认情况下,正则匹配会将整个字符串包括换行符作为匹配源

    1
    2
    3
    4
    5
    6
    7
    8
    比如^foo$默认情况下无法匹配下面内容的foo
    bar
    foo
    baz
    因为上面的这些内容解析的时候是`bar\nfoo\nbaz`
    只能匹配
    foo
    但如果加了多行模式则可以匹配内容一中的foo
  • s dot-all

    让点号匹配包括换行符在内的任何字符

锚点

此锚点非html中的锚点,而是用于限定位置的,锚点本身并不会匹配任何字符。

  • 行开头:^
  • 行结尾:$

行开头与结尾锚点适合搭配多行模式使用

  • 字符边界 \b

    字符边界限制当前位置必须是非字符

  • 非字符边界 \B

    字符边界限制当前位置必须是字符

零宽断言

先行断言

用于验证是否满足某个条件,但只是判断,不管判断成功与否都不会移动当前匹配到的字符的指针。

  • positive
    (?=)

    1
    2
    3
    /_(?=[aeiou])/g
    _a 这里会匹配到前面的下划线,但不会匹配后面的a,这里会匹配到前面的下划线是因为后面跟着a,满足断言
    _f 这里前面的下划线就不会被匹配到,因为后面是f,不满足断言
  • negative
    (?!)

    1
    2
    3
    4
    /_(?![aeiou])/g
    与上面的刚好相反
    _a 这里前面的下划线就不会被匹配到,因为后面是a,不满足断言
    _f 这里会匹配到前面的下划线,但不会匹配后面的f,这里会匹配到前面的下划线是因为后面跟着f,满足断言

    negative一般是为了避免匹配到某个固定组合

    1
    2
    3
    4
    /foo(?!bar)/g
    Y foobaz
    N foobarbaz
    上面的foo会匹配到,下面的foo不能

参考资料中的漫画

Cueball saves the day with regex