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 中可以使用 CompilePOSIXMustCompilePOSIX,简短示例如下:

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 语法,可以查阅:

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}
  1. 字符类在后文中进行解释。

复合匹配/结合(Composite)

Composites  
xy 匹配 xy(x 之后跟随着 y
x|y 匹配 x 或者 y (x 相对更优先)

重复(Repetitions)

  Repetitions
x* 匹配零个或多个 x,优先匹配更多(贪婪)
x+ 匹配一个或多个 x,优先匹配更多(贪婪)
x? 匹配零个或一个 x,优先匹配一个(贪婪)
x{n,m} 匹配 nmx,优先匹配更多(贪婪)
x{n,} 匹配 n 个或多个 x,优先匹配更多(贪婪)
x{n} 精确地匹配 nx
x*? 匹配零个或多个 x,优先匹配更少(非贪婪模式)
x+? 匹配一个或多个 x,优先匹配更少(非贪婪模式)
x?? 匹配零个或一个 x,优先匹配零个(非贪婪模式)
x{n,m}? 匹配 nmx,优先匹配更少(非贪婪模式)
x{n,}? 匹配 n 个或多个 x,优先匹配更少(非贪婪模式)
x{n}? 精确地匹配 nx(非贪婪模式)
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 提供了一个可视化图解:

reFind

References

🔚

留下评论