Golang 正则式语法概述
按:
由于当初并未认真阅读 Wiki 词条和学界渊源,所以对于正则式的简史介绍有若干错误。
今次因而剔除错误,但也并不重写相应段落。
盖因正则式历史描述起来略长,本文若是将其收入,未免篇幅超出预期。
所以暂定为另起一个系列文章来叙述正则式语法及其引擎的实现,该工程规模略大,且实现一个 re-engine 也很难,所以要等到我完成了该引擎之后才能最终成文,目前不能预期到 deadline 为哪一天。
2025-11-11 记
Golang 实际上支持两种正则式语法,其一为标配语法,这是源于 RE2 的语法规则,稍后将会完整阐释,其二为 POSIX ERE 规范,这种规范源于 Perl 正则式规范但有所变化,此规范本文内不做介绍。
Examples
POSIX 方式
POSIX ERE 规范,也就是 egrep 正则式语法,在 Linux/macOS 中可以这样获得:
1
2
egrep 'a*b?c'
grep -E 'a(.*?)c'
详细介绍这种扩展的正则式语法,不是本文的目标,故而略过。
golang 中可以使用 CompilePOSIX 和 MustCompilePOSIX,简短示例如下:
1
2
3
// remove new line chars
reg, _ := regexp.CompilePOSIX("\r\n|\r|\n")
inner = reg.ReplaceAllString(inner, "")
RE2 方式
大多数情况下,我们可能都是采用 Golang 的基本方式,也就是 RE2 规范来做正则式计算,一般是通过 func Compile 或者 func MustCompile 来编译一个正则式模板:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main
import (
"fmt"
"regexp"
)
func main() {
// Compile the expression once, usually at init time.
// Use raw strings to avoid having to quote the backslashes.
var validID = regexp.MustCompile(`^[a-z]+\[[0-9]+\]$`)
fmt.Println(validID.MatchString("adam[23]"))
fmt.Println(validID.MatchString("eve[7]"))
fmt.Println(validID.MatchString("Job[48]"))
fmt.Println(validID.MatchString("snakey"))
}
// Output:
//
// true
// true
// false
// false
RE2 语法在 https://golang.org/s/re2syntax 有完整的描述,本文基于该描述进行阐释。它的一个微有节选的易读版本在 https://pkg.go.dev/regexp/syntax 可以访问,两者可以同时对照以便阅读和相互印证。
简而言之,RE2 是 Russ Cox 实现的 C++ 开源代码库,用发展的眼光来看,这是目前主流正则式引擎中相对最好的一个,优于 PCRE 和 POSIX RE 各实现版本。
区别
RE2 和 POSIX ERE/PCRE 的区别细节太多,较为难以叙述,但确实有人这么做了,一个地方是 Regular Expressions Reference Table of Contents,这里精细地描述了区别,但阅读起来比较费劲;另一个地方是 Regex cheatsheet,较为清晰和概要。简而言之,PCRE/POSIX ERE 和 RE2 的主要区别在 submatch 的处理上,PCRE/POSIX ERE 将会尽量返回更长版本(默认为贪婪模式),而 RE2 则会返回尽可能短的版本(默认为非贪婪模式)。
按:
下面的示例有误,限于时间和其它因素不做订正而保留于此。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main
import (
"fmt"
"regexp"
)
func main() {
pattern := "(foo|foobar)"
str := []byte("foobarbaz")
rPCRE, _ := regexp.Compile(pattern)
rPOSIX, _ := regexp.CompilePOSIX(pattern)
matchesPCRE := rPCRE.Find(str)
fmt.Println("PCRE: ", string(matchesPCRE))
// prints "foo"
matchesPOSIX := rPOSIX.Find(str)
fmt.Println("POSIX ERE: ", string(matchesPOSIX))
// prints "foobar"
}
这个示例源于 playground。
Find(All)?(String)?(Submatch)?(Index)?
所有关于 Golang regexp 包的介绍都不能少却这一小节。regexp 包为正则表达式提供了 16 个查找方法,它们的命名具有一定规律,其格式为 Find(All)?(String)?(Submatch)?(Index)?。
其中的名称短语具有如下特点:
- All:它会继续查找非重叠的后续的字符串,返回全部匹配结果为一个 slice
- String:入参将会采用 string 类型,否则你需要提供 []byte
- Submatch:在返回匹配结果的同时,也返回子表达式(Capturing Group)的匹配项
- Index:
正则式简史
发觉有必要简述一下正则式的各种分支版本。
按,
以下的简史介绍有若干错误之处,故而删除。
正则表达式的 POSIX 规范,分为基本型正则表达式(Basic Regular Expression,BRE)和扩展型正则表达式(Extended Regular Express,ERE)两大流派。在兼容 POSIX 的 UNIX 系统上,grep 和 egrep 之类的工具都遵循 POSIX 规范,一些数据库系统中的正则表达式也匹配 POSIX 规范。grep、vi、sed 都属于 BRE,是历史最早的正则表达式,因此元字符必须转译之后才具有特殊含义。egrep、awk 则属于 ERE,元字符不用转译。(源自 Wiki)
Perl 的正则式解析器 ……
……
如果想了解正规表达式,可以阅读维基词条:
如果想了解 PCRE 语法,请查阅 Regular expression - Wikipedia ,这里完整但缺乏样例。
如果想了解 RE2 语法,可以查阅:
- RE2 语法在 https://golang.org/s/re2syntax 有完整的描述
- 一个微有节选的易读版本在 https://pkg.go.dev/regexp/syntax 可以访问,两者可以同时对照以便阅读和相互印证。
Golang 正则式语法一览
本章节以 Syntax · google/re2 Wiki 为参考基准。
https://pkg.go.dev/regexp/syntax 更简单明快一些,剔除了不支持的条目。
单个字符(Single character)
| kinds of single-character expressions | examples |
|---|---|
| 匹配任意一个字符,如果设置 s = true,则可以匹配换行符 | . |
| 匹配 “字符类” 中的一个字符,即匹配 x, y 或 z | [xyz] |
| 不匹配 “字符类” 中的任一字符,即不匹配 x,y 或 z | [^xyz] |
| 匹配 “Perl类” 中的一个字符 (link) | \d |
| 不匹配 “Perl类” 中的任一字符 | \D |
| 匹配 “ASCII类” 中的一个字符 (link) | [[:alpha:]] |
| 不匹配 “ASCII类” 中的任一字符 | [[:^alpha:]] |
| 匹配 “Unicode 字符类” (one-letter name) 的一个字符 | \pN |
| 匹配 “Unicode 字符类” 的一个字符 | \p{Greek} |
| 不匹配 “Unicode 字符类” (one-letter name) 的任一字符 | \PN |
| 不匹配 “Unicode 字符类” 的任一字符 | \P{Greek} |
- 字符类在后文中进行解释。
复合匹配/结合(Composite)
| Composites | |
|---|---|
xy |
匹配 xy(x 之后跟随着 y) |
x|y |
匹配 x 或者 y (x 相对更优先) |
重复(Repetitions)
| Repetitions | |
|---|---|
x* |
匹配零个或多个 x,优先匹配更多(贪婪) |
x+ |
匹配一个或多个 x,优先匹配更多(贪婪) |
x? |
匹配零个或一个 x,优先匹配一个(贪婪) |
x{n,m} |
匹配 n 到 m 个 x,优先匹配更多(贪婪) |
x{n,} |
匹配 n 个或多个 x,优先匹配更多(贪婪) |
x{n} |
精确地匹配 n 个 x |
x*? |
匹配零个或多个 x,优先匹配更少(非贪婪模式) |
x+? |
匹配一个或多个 x,优先匹配更少(非贪婪模式) |
x?? |
匹配零个或一个 x,优先匹配零个(非贪婪模式) |
x{n,m}? |
匹配 n 到 m 个 x,优先匹配更少(非贪婪模式) |
x{n,}? |
匹配 n 个或多个 x,优先匹配更少(非贪婪模式) |
x{n}? |
精确地匹配 n 个 x(非贪婪模式) |
x{} |
(等价于 x*)(不支持)VIM |
x{-} |
(等价于 x*?)(不支持)VIM |
x{-n} |
(等价于 x{n}?)(不支持)VIM |
x= |
(等价于 x?)(不支持)VIM |
启动限制:计数形式 x{n,m}、x{n,} 和 x{n} 最小或最大重复个数不能超过 1000。 无限制的重复不受此限制约束。
| 所有格重复 | |
|---|---|
| x*+ | 匹配零个或任意个 x,所有格(不支持) |
| x++ | 匹配至少一个 x,所有格(不支持) |
| x?+ | 匹配零个或一个 x,所有格(不支持) |
| x {n,m} + | 匹配 n…或 m 个 x,所有格(不支持) |
| x{n,}+ | 匹配至少 n 个 x,所有格(不支持) |
| x{n}+ | 匹配确定的 n 个 x,所有格(不支持) |
分组(Grouping)
| Grouping | |
|---|---|
(re) |
编号捕获组(子匹配) |
(?P<name>re) |
命名 & 编号捕获组(子匹配) |
(?<name>re) |
命名 & 编号捕获组(子匹配)(不支持) |
(?'name're) |
命名 & 编号捕获组(子匹配)(不支持) |
(?:re) |
非捕获组 |
(?flags) |
在当前组中设置标志;非捕获 |
(?flags:re) |
在表达式中设置标志;非捕获 |
(?#text) |
注释(不支持) |
(?|x|y|z) |
分支编号重置(不支持) |
(?>re) |
表达式所有格匹配 (不支持) |
re@> |
表达式所有格匹配(不支持)VIM |
%(re) |
非捕获组(不支持) VIM |
上表中的 flags 可以是:
| Flags | |
|---|---|
i |
不区分大小写(默认为 false) |
m |
多行模式: ^ 和 $ 匹配行首/尾,以及文本开头/结尾(默认为 false) |
s |
允许 . 匹配 \n (默认为 false) |
U |
非贪婪模式:以 x*? 替换 x*、x+? 替换 x+ 等(默认为 false) |
标记语法为 xyz (已设置)或 -xyz (清除)或 xy-z (设置为 xy,清除 z)。
Flag syntax is xyz (set) or -xyz (clear) or xy-z (set xy, clear z).
空字符串
| Empty strings | |
|---|---|
^ |
文本开始或行首(m = true) |
$ |
文本开始或行首(m = true) |
\A |
文本开头 |
\b |
匹配 ASCII 单词边界(\w 表示一端,\W、\A 或 \z 表示另一端) |
\B |
匹配非 ASCII 单词边界 |
\g |
匹配正在搜索的从属文本开头(不支持) PCRE |
\G |
匹配上一个匹配的结尾(不支持) PERL |
\Z |
匹配必须出现在文本末尾,或在文本末尾换行前的位置(不支持) |
\z |
匹配文本末尾 |
(?=re) |
前向肯定界定符(不支持) |
(?!re) |
前向否定界定符(不支持) |
(?<=re) |
后向肯定界定符(不支持) |
(?<!re) |
后向否定界定符(不支持) |
re& |
前向肯定界定符(不支持)VIM |
re@= |
前向肯定界定符(不支持)VIM |
re@! |
前向否定界定符(不支持)VIM |
re@<= |
后向肯定界定符(不支持)VIM |
re@<! |
后向否定界定符(不支持)VIM |
\zs |
设置匹配开始(同 \K)(不支持) VIM |
\ze |
设置匹配结尾(不支持) VIM |
\%^ |
匹配文件开头(不支持) VIM |
\%$ |
匹配文件结尾(不支持) VIM |
\%V |
在屏幕上匹配(不支持)VIM |
\%# |
从光标位置匹配(不支持) VIM |
\%'m |
在标记 m 的位置匹配(不支持) VIM |
\%23l |
在第 23 行匹配(不支持)VIM |
\%23c |
在第 23 列匹配(不支持)VIM |
\%23v |
在虚拟第 23 列匹配(不支持)VIM |
转义序列
| Escape sequences | |
|---|---|
\a |
报警符 bell (≡ \007) |
\f |
换页符 form feed (≡ \014) |
\t |
水平制表符 horizontal tab (≡ \011) |
\n |
换行符 newline (≡ \012) |
\r |
回车符 carriage return (≡ \015) |
\v |
垂直制表符 vertical tab character (≡ \013) |
\* |
字面量 *, 匹配任意标点字符 * |
\123 |
匹配八进制字符代码(最多三位) |
\x7F |
匹配十六进制字符代码(最多两位) |
\x{10FFFF} |
匹配十六进制字符代码 |
\C |
匹配单字节,即使在 UTF-8 模式下 |
\Q...\E |
匹配文本 ... ,即使 ... 中包含标点 |
\1 |
匹配反向引用(不支持) |
\b |
匹配退格 (不支持)(使用 \010) |
\cK |
匹配控制字符 ^K (不支持)(使用 \001 等) |
\e |
匹配转义符 (不支持)(使用 \033) |
\g1 |
匹配反向引用(不支持) |
\g{1} |
匹配反向引用(不支持) |
\g{+1} |
匹配反向引用(不支持) |
\g{-1} |
匹配反向引用(不支持) |
\g{name} |
匹配已命名反向引用(不支持) |
\g<name> |
匹配子例程调用(不支持) |
\g'name' |
匹配子例程调用(不支持) |
\k<name> |
匹配已命名反向引用(不支持) |
\k'name' |
匹配已命名反向引用(不支持) |
\lX |
匹配小写 X(不支持) |
\ux |
匹配大写 x(不支持) |
\L...\E |
匹配小写文本 ... (不支持) |
\K |
重置 $0 开头(不支持) |
\N{name} |
匹配已命名 Unicode 字符(不支持) |
\R |
匹配换行符(不支持) |
\U...\E |
匹配大写文本 ... (不支持) |
\X |
匹配扩展 Unicode 序列(不支持) |
\%d123 |
匹配十进制字符 123(不支持) VIM |
\%xFF |
匹配十六进制字符 FF (不支持) VIM |
\%o123 |
匹配八进制字符 123(不支持) VIM |
\%u1234 |
匹配 Unicode 字符 0x1234(不支持)VIM |
\%U12345678 |
匹配 Unicode 字符 0x12345678(不支持)VIM |
字符组元素(字符类)
| Character class elements | |
|---|---|
x |
单个字符 |
A-Z |
字符范围(含) |
\d |
匹配 Perl 字符类 |
[:foo:] |
匹配 ASCII 字符类 foo |
\p{Foo} |
匹配 Unicode 字符类 Foo |
\pF |
匹配 Unicode 字符类 F(单字母名称) |
作为字符类元素命名的字符组
| Named character classes as character class elements | |
|---|---|
[\d] |
数字字符 (≡ \d) |
[^\d] |
非数字字符 (≡ \D) |
[\D] |
非数字字符 (≡ \D) |
[^\D] |
非非数字字符、即数字字符 (≡ \d) |
[[:name:]] |
匹配在字符类内部命名的 ASCII 类 (≡ [:name:]) |
[^[:name:]] |
匹配在排除型字符类内部命名的 ASCII 类 (≡ [:^name:]) |
[\p{Name}] |
匹配在字符类内部命名的 Unicode 属性 (≡ \p{Name}) |
[^\p{Name}] |
匹配在排除型字符类内部命名的 Unicode 属性 (≡ \P{Name}) |
Perl 字符组(仅限所有 ASCII 码)
| Perl character classes (all ASCII-only) | |
|---|---|
\d |
数字 (≡ [0-9]) |
\D |
非数字 (≡ [^0-9]) |
\s |
白空格 (≡ [\t\n\f\r ]) |
\S |
非白空格 (≡ [^\t\n\f\r ]) |
\w |
整个单词 (≡ [0-9A-Za-z_]) |
\W |
非整个单词 (≡ [^0-9A-Za-z_]) |
\h |
水平空格 (不支持) |
\H |
非水平空格 (不支持) |
\v |
垂直空格 (不支持) |
\V |
非垂直空格 (不支持) |
ASCII 字符类
| ASCII character classes | ||
|---|---|---|
[[:alnum:]] |
字母和数字 (≡ [0-9A-Za-z]) |
|
[[:alpha:]] |
字母 (≡ [A-Za-z]) |
|
[[:ascii:]] |
ASCII字符 (≡ [\x00-\x7F]) |
|
[[:blank:]] |
空白字符 (≡ [\t ]) |
|
[[:cntrl:]] |
控制字符 (≡ [\x00-\x1F\x7F]) |
|
[[:digit:]] |
数字 (≡ [0-9]) |
|
[[:graph:]] |
图形字符,可打印字符,可见字符 (≡ [!-~] ≡ [A-Za-z0-9!"#$%&'()*+,\-./:;<=>?@[\\\]^_````{ |
}~]`) |
[[:lower:]] |
小写字符 (≡ [a-z]) |
|
[[:print:]] |
可打印字符 (≡ [ -~] ≡ [ [:graph:]]) |
|
[[:punct:]] |
标点字符 (≡ [!-/:-@[-````{-~]`) |
|
[[:space:]] |
白空格 (≡ [\t\n\v\f\r ]) |
|
[[:upper:]] |
大些字符 (≡ [A-Z]) |
|
[[:word:]] |
整个单词 (≡ [0-9A-Za-z_]) |
|
[[:xdigit:]] |
十六进制字符 (≡ [0-9A-Fa-f]) |
Unicode 字符类名称 - 常规类别
| Unicode character class names–general category | |
|---|---|
C |
其它 |
Cc |
control |
Cf |
format |
Cn |
未赋值码点 (NOT SUPPORTED) |
Co |
私有用途 |
Cs |
代理项 surrogate |
L |
字母 |
LC |
大小写字母(不支持) |
L& |
大小写字母(不支持) |
Ll |
小写字母 |
Lm |
修饰字母 |
Lo |
其他字母 |
Lt |
首字母大写 |
Lu |
大写字母 |
M |
标记 mark |
Mc |
间距标记 spacing mark |
Me |
封闭标记 enclosing mark |
Mn |
非间距标记 non-spacing mark |
N |
数字 number |
Nd |
十进制数字 decimal number |
Nl |
字母或数字 letter number |
No |
其它数字 other number |
P |
标点符号 punctuation |
Pc |
连接符 connector punctuation |
Pd |
短划线 dash punctuation |
Pe |
结束标点 close punctuation |
Pf |
后引号 final punctuation |
Pi |
前引号 initial punctuation |
Po |
其它标点符号 other punctuation |
Ps |
开始标点 open punctuation |
S |
符号 symbol |
Sc |
货币符号 currency symbol |
Sk |
修饰符符号 modifier symbol |
Sm |
数学符号 math symbol |
So |
其它符号 other symbol |
Z |
分隔符 separator |
Zl |
行分隔符 line separator |
Zp |
段落分隔符 paragraph separator |
Zs |
空白分隔符 space separator |
Unicode 字符类名称 - 文字系统
| Unicode character class names–scripts |
|---|
阿德拉姆Adlam |
阿霍姆语Ahom |
安纳托利亚 _ 象形文字Anatolian_Hieroglyphs |
阿拉伯语Arabic |
亚美尼亚语Armenian |
阿维斯陀语Avestan |
巴厘文Balinese |
巴姆穆文Bamum |
Bassa_Vah |
巴塔克文Batak |
孟加拉语Bengali |
拜克舒克文Bhaiksuki |
汉语拼音字母Bopomofo |
婆罗米文Brahmi |
布莱叶盲文Braille |
布吉文Buginese |
布锡语Buhid |
加拿大 _ 澳大利亚土著语Canadian_Aboriginal |
卡里亚文Carian |
高加索 _ 阿尔巴尼亚语Caucasian_Albanian |
占文Chakma |
Cham |
切罗基语Cherokee |
花剌子模语Chorasmian |
通用Common |
科普特语Coptic |
楔形文字Cuneiform |
塞浦路斯语Cypriot |
Cypro_Minoan |
西里尔字母Cyrillic |
德塞莱特文Deseret |
梵文Devanagari |
Dives_Akuru |
多格兰语Dogra |
杜普洛伊速记体Duployan |
埃及 _ 象形文字Egyptian_Hieroglyphs |
爱尔巴桑语Elbasan |
埃利迈语Elymaic |
埃塞俄比亚文Ethiopic |
格鲁吉亚语Georgian |
格拉哥里语Glagolitic |
哥特语Gothic |
格兰塔字母Grantha |
希腊语Greek |
古吉拉特语Gujarati |
Gunjala_Gondi |
锡克教文Gurmukhi |
汉语Han |
韩语Hangul |
Hanifi_Rohingya |
汉奴劳族文Hanunoo |
哈特兰文Hatran |
希伯来语Hebrew |
日文Hiragana |
英制文字 _ 阿拉姆语Imperial_Aramaic |
继承Inherited |
碑文 _ 巴拉维语Inscriptional_Pahlavi |
碑文 _ 帕提亚语Inscriptional_Parthian |
爪哇文Javanese |
凯提文Kaithi |
埃纳德语Kannada |
片假名Katakana |
克耶 _ 列支敦士登Kayah_Li |
卡罗须提文Kharoshthi |
契丹 _小_文字Khitan_Small_Script |
高棉语Khmer |
克吉奇文Khojki |
信德文Khudawadi |
老挝语Lao |
拉丁语Latin |
雷布查文Lepcha |
林布文Limbu |
线性 _ALinear_A |
线性 _BLinear_B |
僳文傈Lisu |
利西亚文Lycian |
吕底亚文Lydian |
马哈詹语Mahajani |
望加锡语Makasar |
马拉雅拉姆语Malayalam |
阿拉米文Mandaic |
摩尼文Manichaean |
Marchen |
Masaram_Gondi |
梅德法伊德林文Medefaidrin |
梅泰族 _ 曼尼普尔文Meetei_Mayek |
门德 _ 门迪文Mende_Kikakui |
麦罗埃 _ 手写体Meroitic_Cursive |
麦罗埃 _ 象形文字Meroitic_Hieroglyphs |
苗文Miao |
莫迪文Modi |
蒙古语Mongolian |
毛里塔尼亚乌吉亚Mro |
穆尔塔尼Multani |
缅甸Myanmar |
纳巴泰Nabataean |
楠迪梵文Nandinagari |
New_Tai_Lue |
Newa |
Nko |
女书Nushu |
Nyiakeng_Puachue_Hmong |
欧甘字母Ogham |
Ol_Chiki |
古语 _ 匈牙利语Old_Hungarian |
古语 _ 意大利语Old_Italic |
古语 _ 北部 _ 阿拉伯语Old_North_Arabian |
古语 _ 彼尔姆语Old_Permic |
古语 _ 波斯语Old_Persian |
古语 _ 古索格代亚纳语Old_Sogdian |
古语 _ 南部 _ 阿拉伯语Old_South_Arabian |
古语 _ 突厥语Old_Turkic |
Old_Uyghur |
奥里雅语Oriya |
欧塞奇语Osage |
奥斯曼亚字母Osmanya |
救世苗文 _ 苗语Pahawh_Hmong |
帕米拉语Palmyrene |
Pau_Cin_Hau |
Phags_Pa |
腓尼基语Phoenician |
Psalter_Pahlavi |
勒姜语Rejang |
古北欧文字Runic |
撒马利亚文Samaritan |
索拉什特拉文Saurashtra |
夏拉达文Sharada |
萧伯纳文Shavian |
悉昙文字Siddham |
手语书写体SignWriting |
僧伽罗语Sinhala |
粟特语Sogdian |
Sora_Sompeng |
索永布语Soyombo |
巽他语Sundanese |
Syloti_Nagri |
叙利亚语Syriac |
他加禄语Tagalog |
塔班瓦语Tagbanwa |
Tai_Le |
Tai_Tham |
Tai_Viet |
泰克里文Takri |
泰米尔语Tamil |
西夏语Tangsa |
Tangut |
泰卢固语Telugu |
它拿字母Thaana |
泰语Thai |
藏语Tibetan |
提夫纳语Tifinagh |
Tirhuta |
Toto |
乌加里特语Ugaritic |
瓦依语Vai |
Vithkuqi |
万秋文Wancho |
Warang_Citi |
雅兹迪语Yezidi |
彝语Yi |
Zanabazar_Square |
Vim 字符类
| Vim character classes | |
|---|---|
\i |
匹配标识符字符(不支持) VIM |
\I |
\i 不包括数字字符(不支持)VIM |
\k |
匹配关键字字符(不支持)VIM |
\K |
\k 不包括数字字符(不支持)VIM |
\f |
匹配文件名称字符(不支持)VIM |
\F |
\f 不包括数字字符(不支持)VIM |
\p |
匹配可打印字符(不支持)VIM |
\P |
\p 不包括数字字符(不支持)VIM |
\s |
匹配空白字符 (≡ [ \t]) (NOT SUPPORTED) VIM |
\S |
匹配非空白字符 (≡ [^ \t]) (NOT SUPPORTED) VIM |
\d |
数字 (≡ [0-9]) VIM |
\D |
非 \d VIM |
\x |
十六进制数字 (≡ [0-9A-Fa-f]) (NOT SUPPORTED) VIM |
\X |
非 \x (NOT SUPPORTED) VIM |
\o |
八进制数字 (≡ [0-7]) (NOT SUPPORTED) VIM |
\O |
非 \o (NOT SUPPORTED) VIM |
\w |
单词 VIM |
\W |
非 \w VIM |
\h |
匹配单词起始字符 (NOT SUPPORTED) VIM |
\H |
非 \h (NOT SUPPORTED) VIM |
\a |
匹配字母字符 (NOT SUPPORTED) VIM |
\A |
非 \a (NOT SUPPORTED) VIM |
\l |
小写字符 (NOT SUPPORTED) VIM |
\L |
非小写字符 (NOT SUPPORTED) VIM |
\u |
大写字符 (NOT SUPPORTED) VIM |
\U |
非大写字符 (NOT SUPPORTED) VIM |
\_x |
\x 加上换行符,匹配任意 x (NOT SUPPORTED) VIM |
\c |
忽略大小写 (NOT SUPPORTED) VIM |
\C |
匹配大小写 (NOT SUPPORTED) VIM |
\m |
magic (NOT SUPPORTED) VIM |
\M |
nomagic (NOT SUPPORTED) VIM |
\v |
verymagic (NOT SUPPORTED) VIM |
\V |
verynomagic (NOT SUPPORTED) VIM |
\Z |
忽略 Unicode 组合字符的不同 (NOT SUPPORTED) VIM |
Magic
| Magic | |
|---|---|
(?{code}) |
PERL 中的任意 Perl 代码(不支持) |
(??{code}) |
PERL 中延迟的任意 Perl 代码(不支持) |
(?n) |
递归调用 regexp 捕获组 n (不支持) |
(?+n) |
递归调用相对组 +n (不支持) |
(?-n) |
递归调用相对组 -n (不支持) |
(?C) |
PCRE 回调(不支持) PCRE |
(?R) |
递归调用整个 regexp (等价于 (?0))(不支持) |
(?&name) |
递归调用已命名组(不支持) |
(?P=name) |
匹配已命名反向引用(不支持) |
(?P>name) |
递归调用已命名组(不支持) |
(?(cond)true|false) |
条件分支(不支持) |
(?(cond)true) |
条件分支(不支持) |
(*ACCEPT) |
让 regexps 更类似于 Prolog (不支持) |
(*COMMIT) |
(NOT SUPPORTED) |
(*F) |
(NOT SUPPORTED) |
(*FAIL) |
(NOT SUPPORTED) |
(*MARK) |
(NOT SUPPORTED) |
(*PRUNE) |
(NOT SUPPORTED) |
(*SKIP) |
(NOT SUPPORTED) |
(*THEN) |
(NOT SUPPORTED) |
(*ANY) |
设置换行约定(不支持) |
(*ANYCRLF) |
(NOT SUPPORTED) |
(*CR) |
(NOT SUPPORTED) |
(*CRLF) |
(NOT SUPPORTED) |
(*LF) |
(NOT SUPPORTED) |
(*BSR_ANYCRLF) |
设置 \R 约定(不支持) PCRE |
(*BSR_UNICODE) |
(NOT SUPPORTED) PCRE |
后记
本文主要目的是回顾和整理一个 cheatsheet。很显然,一篇文章是不可能教会你正则式的,所以本文也不怎么给示例,要想讲清楚会需要太多示例。
作为一个示例,cmdr 包含一个工具函数 UnescapeUnicode,其源码为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// UnescapeUnicode 解码 \uxxxx 为 unicode 字符; 但是输入的 b 应该是 yaml 格式
func UnescapeUnicode(b []byte) string {
b = reFind.ReplaceAllFunc(b, expandUnicodeInYamlLine)
return string(b)
}
func expandUnicodeInYamlLine(line []byte) []byte {
// TODO: restrict this to the quoted string value
return reFindU.ReplaceAllFunc(line, expandUnicodeRune)
}
func expandUnicodeRune(esc []byte) []byte {
ri, _ := strconv.ParseInt(string(esc[2:]), 16, 32)
r := rune(ri)
repr := make([]byte, utf8.RuneLen(r))
utf8.EncodeRune(repr, r)
return repr
}
var reFind = regexp.MustCompile(`[^\s\:]+\:\s*["']?.*\\u.*["']?`)
jex.im 为这个 Pattern 提供了一个可视化图解:

References
- https://pkg.go.dev/regexp
- https://pkg.go.dev/regexp#Compile
- https://pkg.go.dev/regexp#MustCompile
- https://pkg.go.dev/regexp#CompilePOSIX
- https://pkg.go.dev/regexp#MustCompilePOSIX
- regex - What is the difference between regexp.Compile and regexp.CompilePOSIX? - Stack Overflow
- https://golang.org/s/re2syntax
- https://pkg.go.dev/regexp/syntax
- 微软的 RE2
- 正则表达式 - 维基百科,自由的百科全书
🔚
留下评论