Skip to content

MXXXXXS/Introduction-to-JS-Regex

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 

Repository files navigation

JS 正则表达式的介绍

什么是正则表达式(Regular Expressions)

正则表达式是对文本模式的描述

在自然语言中,1, 2, 3 被称为 数字, 水, 火, 风 被称为 物质, 数字, 物质是对事物的描述

类似的,在一段文本中,a, b, c可以称为 单词字符, 文本 1, 2, 3可以称为 数字字符

单词字符, 数字字符 这些概念用符号表示,这些符号就是正则表达式

正则表达式是一种语言, 专用于模式匹配领域的语言(DSL, Domain-specific language)

为什么叫“JS 正则表达式的介绍”, 为什么要加上“JS”

正则表达式是为了解决模式匹配这个问题产生的一种方法

其有很多种实现, 不同编程语言有不同的正则表达式实现,表达式的语法也有差异

这里讨论的是 JS 里的正则表达式语法

更多类型的正则表达式细节可以参考这里

测试表达式的工具

为了方便练习测试编写正则表达式,这里推荐一个工具网站 regexr

常见的表达式

像上面提到的 单词字符 对应的符号是 \w, 数字字符 对应的是\d

还有很多其他的符号,下面来看一些常见的表达式

单个字符

单个的字符本身就是一种模式

/Regex/

会匹配

"Regex"

一类字符

要匹配所有的单词字符

/\w/

会匹配

"a", "b", "_", "0"

注意/\w/里的\代表转义,/w/会匹配 "w"

/\W//\w/的反面(非单词字符), /\D//\d/的反面(非数字字符)

多者之一

使用[]

使用[]来包含多个模式,会匹配多个模式中的一个

/[abc]/

会匹配

"a", "b", "c"

但不会匹配除这三个之外的别的字符

范围

[]里,-具有表示范围的功能

上方的表达式还可以写成

/[a-c]/

不匹配

[]里,^放置在开头表示不匹配

/[^a-c]/

表示不匹配a, b, c, 或表示匹配除a, b, c之外的别的字符

使用|

|类似“或”的含义,上面的例子也可以写成

/a|b|c/
/[a-c]|[e-g]/

捕获分组

()可以用来对匹配到的内容分组

比如版本号匹配, 使用

/(\d+).(\d+).(\d+)/

来匹配

"2.3.4"

使用match

"2.3.4".match(/(\d+).(\d+).(\d+)/)

返回

['2.3.4', '2', '3', '4']

返回的第一项是整个匹配结果,其余内容是各个括号捕获到的内容

数量指定

?代表某个模式的 0 或 1 次

+代表某个模式的 1 或多次

*代表某个模式的 0 或多次

/a*/

匹配

"", "a", "aa", "aaa"

{n}指定具体的数量

/a{2}/

只匹配

"aa"

{m,n}指定范围

/a{1,3}/

匹配

"a", "aa", "aaa"

{m,}会至少匹配 m 个

/a{1,}/

匹配

"a", "aa", "aaa", "aaaa"

范围匹配时,尽量多匹配还是少匹配(贪婪模式和惰性模式)

比如

"aaaaa"

使用

/a{1,3}/

会匹配到

"aaa"

这是默认的“尽量多匹配”的模式(贪婪模式)

如果加上?

/a{1,3}?/

会匹配到

"a"

这是“尽量少匹配”的模式(惰性模式)

位置

字符之间的间隔被称为"位置", 有一些正则符号可以用来代表位置, 用来辅助匹配

行首, 行尾

比如

"22.33"

要匹配小数点前面的部分, 可以用

/^\d*/

来匹配, 其中^代表了行首的位置

要匹配小数点后面的部分, 可以用

/\d*$/

来匹配, 其中$代表了行末的位置

单词边界

单词字符非单词字符(比如标点符号)之间的间隔用\b表示

比如要统一日期的表示, 将2022.6.28, 2022/6/28都统一成2022-6-28

'2022.6.28'.split(/\b\W*\b/).join('-')
'2022/6/28'.split(/\b\W*\b/).join('-')

Lookahead and lookbehind, Positive and Negative

Lookahead lookbehind
Positive (?=p) (?<=p)
Negative (?!p) (?<!p)

其中p代表一个模式

"Positive Lookahead"指的是匹配p前面的位置, "Positive lookbehind"指的是匹配p后面的位置

"Negative Lookahead"指的是不匹配p前面的位置, "Negative lookbehind"指的是不匹配p后面的位置

举例

/Task\d (?=(done))/g

会匹配完成的Task(后面跟着"done")

image-20220628221120638

要匹配没有完成的项, 使用

/Task\d (?!(done))/g

image-20220628221352258

Flags

上面的表达式出现了g, 这是一个用于控制表达式行为的标志位

参考Advanced searching with flags

Flag Description Corresponding property
d Generate indices for substring matches. RegExp.prototype.hasIndices
g Global search. RegExp.prototype.global
i Case-insensitive search. RegExp.prototype.ignoreCase
m Multi-line search. RegExp.prototype.multiline
s Allows . to match newline characters. RegExp.prototype.dotAll
u "unicode"; treat a pattern as a sequence of unicode code points. RegExp.prototype.unicode
y Perform a "sticky" search that matches starting at the current position in the target string. See sticky. RegExp.prototype.sticky

表达式应用

格式校验

这个很常见, 校验各种格式

比如Meflow里金额字段的识别

image-20220628222702335

以及相关测试用例

image-20220628222817023

内容提取

image-20220628223116546

其中/\p{sc=Han}/代表一个汉字, 参考Unicode property escapes

文本替换

String.prototype.replace()非常强大, 这里特指其第二个参数是一个replacerFunction的时候

比如一个获取某篇博客文章的某个评论的api格式类似

Get /api/:blogId/comments/:commentId

要构造一个请求路径, 比如blogId: 14, commentId: 2

const apiSchema = "/api/:blogId/comments/:commentId"
const apiArgs = {
  blogId: 14,
  commentId: 2,
}
apiSchema.replace(/:(\w+)/g, (_, p) => {
  return apiArgs[p]
})

会返回

'/api/14/comments/2'

资料推荐

JavaScript正则表达式迷你书(1.1版).pdf: 一本小册子, 后面有个速查表非常方便

https://javascript.info/regular-expressions: 非常棒的在线教程

https://regexr.com/: 非常好用的正则测试网站

扩展阅读

这是一定没人会仔细看的一节, 放最后, 供感兴趣的读者参考

注意:实用中的正则表达式和计算理论意义下的正则表达式是不同的

这里介绍一下计算理论中的正则表达式

本节内容修正感谢:geelaw

定义

摘自: Introduction to the Theory of Computation

豆瓣链接: 计算理论导引(英文版·第3版)

正则表达式描述了一个 regular language, P64

image-20220628210619053

以上表述中的一些符号含义, P44

image-20220628212703461

JS正则表达按照定义来看, 1-6条可以分别对应

  1. /a/对应"a"
  2. //对应空字符串
  3. /[]/对应不匹配任何字符串
  4. /a|b/对应"a"或"b"
  5. /ab/对应"ab"
  6. /a*/对应任意数量的"a"

注意: 这不是一个自循环的定义, P65

image-20220628210822554

什么是language, P14

image-20220628211555735

什么是string, P14

image-20220628211809153

什么是alphabet, P13

image-20220628212057818

局限性

image-20220628214147331

正则表达式只能处理一部分的context-free language

像嵌套匹配的括号(balanced brackets)就没法用一个正则去描述

可以用Pumping lemma去证明不是context-free language(不能证明是,但可以证明不是)


Creative Commons License

MXXXXXS

This work is licensed under a Creative Commons Attribution 4.0 International License

About

JS正则表达式的介绍

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published