低创, 求放过, 优点是比较 简洁
只要有人不知道就不算火星(≧∇≦)ノ
原地址: https://github.com/MXXXXXS/Introduction-to-JS-Regex
如有资料侵权, 请立即联系本人删除, 可以在 Github 里发 issue
正则表达式是对文本模式的描述
在自然语言中,1, 2, 3
被称为 数字
, 水, 火, 风
被称为 物质
, 数字
, 物质
是对事物的描述
类似的,在一段文本中,a, b, c
可以称为 单词字符
, 文本 1, 2, 3
可以称为 数字字符
将 单词字符
, 数字字符
这些概念用符号表示,这些符号就是正则表达式
正则表达式是一种语言, 专用于模式匹配领域的语言(DSL, Domain-specific language)
正则表达式是为了解决模式匹配这个问题产生的一种方法
其有很多种实现, 不同编程语言有不同的正则表达式实现,表达式的语法也有差异
这里讨论的是 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-c)(e-g)]/
匹配
"a", "b", "c"
"e", "f", "g"
|
|
类似“或”的含义,上面的例子也可以写成
/a|b|c/
/[a-c]|[e-g]/
?
代表某个模式的 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 | 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")
要匹配没有完成的项, 使用
/Task\d (?!(done))/g
上面的表达式出现了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 里金额字段的识别
以及相关测试用例
其中/\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://github.com/qdlaoyao/js-regex-mini-book/raw/master/JavaScript 正则表达式迷你书( 1.1 版).pdf): 一本小册子, 后面有个速查表非常方便
https://javascript.info/regular-expressions: 非常棒的在线教程
https://regexr.com/: 非常好用的正则测试网站
这是一定没人会仔细看的一节, 放最后, 供感兴趣的读者参考
摘自: Introduction to the Theory of Computation
豆瓣链接: 计算理论导引(英文版·第 3 版)
正则表达式 R 是一种language, P64
以上表述中的一些符号含义, P44
JS 正则表达按照定义来看, 1-6 条可以分别对应
注意: 这不是一个自循环的定义, P65
什么是language, P14
什么是string, P14
什么是alphabet, P13
正则表达式只能处理有限的 context-free language
像嵌套匹配的括号就没法用一个正则去描述
是否是 context-free language 可以用Pumping lemma去判断
This work is licensed under a Creative Commons Attribution 4.0 International License
1
tanranran 2022-06-28 23:33:25 +08:00
很棒!
|
2
Jat001 2022-06-28 23:55:25 +08:00
说单词字符不如说 a-zA-Z0-9_ 减少歧义
|
3
Moeyua 2022-06-29 00:17:37 +08:00 via iPhone
迷你书的链接 404 了
|
4
geelaw 2022-06-29 00:47:54 +08:00 2
>多组模式之一
>使用()来表示一组模式 > >/[(a-c)(e-g)]/ >匹配 > >"a", "b", "c" >"e", "f", "g" 这似乎是误解,在 [] 里面 () 没有特别的含义,/[(a-c)(e-g)]/ 恰好匹配 abcefg() 这 8 个字符里的任意一个,等同于 /[abcefg)(]/。 >扩展阅读 >正则表达式的定义 这里你应该让读者注意实用中的正则表达式和计算理论意义下的正则表达式是不同的,实用意义的正则表达式(例如 JavaScript )的可以描述 non-regular language ,例如 /[01]*\1/ 所匹配的串的集合就不是 regular ,也不是 context-free 。再比如,零宽断言(包括 \b 等)也不能直接用计算理论意义下的正则表达式表达。 >正则表达式 R 是一种 language, P64 这是误解,正则表达式描述了一个 regular language ,但本身不是一个 language ,给定字母表的所有正则表达式的集合是另一个 language ,且后面这个 language 不是 regular 。 >JS 正则表达按照定义来看, 1-6 条可以分别对应 >2. /./对应任意字符 >3. //对应空 这是误解,2 (\varepsilon) 对应的是 //,它匹配长度为 0 的字符串,3 (\varnothing) 对应的是 /[]/,它不匹配任何字符串。 >正则表达式的局限性 >正则表达式只能处理有限的 context-free language >像嵌套匹配的括号就没法用一个正则去描述 >是否是 context-free language 可以用 Pumping lemma 去判断 什么是“有限的 context-free language”?有限 language 都是 regular 。此外,pumping lemma 不能用来证明一个语言是 regular (可以用来证明一个语言不是 regular )。 |
5
Trello 2022-06-29 00:58:17 +08:00 via iPhone
一直都感觉正则好难学。。
|
7
SuperMaxine 2022-06-29 09:07:56 +08:00 via Android
请教下楼主,没太懂倒数第二句话
> 像嵌套匹配的括号就没办法用一个正则去描述 啥叫嵌套匹配的括号呀😂 |
8
yaocai321 2022-06-29 09:57:47 +08:00
下次抄你的
|
9
MXXXXXS OP @SuperMaxine balanced brackets, 可以参考这个: https://everything2.com/title/pumping+lemma+proof+that+the+balanced+braces+language+is+not+regular
|
10
hunter0122 2022-06-29 12:42:41 +08:00
下次我也要抄你的 xd
|
11
MXXXXXS OP 补一下链接:
[JavaScript 正则表达式迷你书( 1.1 版).pdf]( https://github.com/qdlaoyao/js-regex-mini-book/raw/master/JavaScript%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E8%BF%B7%E4%BD%A0%E4%B9%A6%EF%BC%881.1%E7%89%88%EF%BC%89.pdf) 原文已更新,感谢 geelaw |
12
SuperMaxine 2022-06-29 15:01:54 +08:00 1
@MXXXXXS 感谢给出链接,但是看过之后我觉得您好像有些概念混淆了。链接中证明了 balance brackets 语言不是正规语言,可是正则表达式并不是一个 balance brackets 语言。如果您点进对 balance brackets 语言的超链接,可以看到其定义是:字母表={`(`,`)`},且`(`和`)`的数量相等。但正则表达式中,括号是操作符而不是字符(虽然字母表中可以有`(`和`)`,通过转义`\(`和`\)`来表达,但是作为字符时并不要求两者数量相等),所以这个例子并不能证明正则表达式无法表达全部的上下文无关语言。
实际上,我们实际使用的正则表达式是可以表达所有上下文无关语言的:见 https://www.npopov.com/2012/06/15/The-true-power-of-regular-expressions.html#matching-context-free-languages 我查了一会儿资料,发现这一切的混乱来自于工程上的“正则表达式”和 CS 的“正则表达式”之间的冲突。就计算机科学领域而言,您最后一个小节引用的内容是正确的:正则语言确实是上下文无关语言的子集;但现实工程中的正则表达式已经加入众多,像您前面所介绍的,可以增强表达能力的“特性”(如 lookaround 、反向引用等),从而不在是计算机科学意义上的“正则语言”,甚至不再是上下文无关语言。两者的英文表达都可以是“regular expression”,就我找到的英文文献[1][2],现在学术中好像倾向于保留 CS 中的用法而将工程上的“正则表达式”写为“regex”或“regexp”;而在中文中我觉得可以在讨论计科的内容时避免使用“正则文法”、“正则表达式”等表述而改为“正规文法”、“正规式”来避免混乱。 前面您写的是真不错,后面因为我自己也不太懂较了会儿真,没想到看个帖子还能复习一遍编译原理哈哈哈 [1] https://www.usenix.org/conference/usenixsecurity22/presentation/mclaughlin [2] https://www.researchgate.net/publication/228847164_Converting_regexes_to_Parsing_Expression_Grammars |
13
MXXXXXS OP @SuperMaxine 哇哦,非常感谢!这部分理论知识自己确实不熟悉,感谢您详细的解释!
|
14
littlewing 2022-06-29 19:28:21 +08:00
我以为你要介绍正则表达式的匹配算法,用法这种东西有啥好介绍的
|
15
sxiaojian 2022-06-30 16:54:16 +08:00
用法挺需求介绍的。
感觉正则很怪,用一次需要再去了解一次 |
16
rhli1995 2022-07-01 13:21:35 +08:00
下次我也抄你哈哈
|
17
rockjike 2022-09-29 11:17:49 +08:00
老哥, 准备抄你哈哈
|