查看: 754|回复: 7

[交流] 简明正则表达式介绍【转载自开源阅读】

[复制链接]

16

听众

0

收听

13

好友

贡士

Rank: 7Rank: 7Rank: 7

UID
155378
积分
2986
回帖
1024
主题
67
铜币
44306
威望
2435
银币
0
贡献
0
发书数
57
注册时间
2023-6-14
最后登录
2024-4-28
在线时间
1538 小时
发表于 2023-11-18 11:28 | 显示全部楼层 |阅读模式
本帖最后由 edennow 于 2024-4-15 14:13 编辑

在开源阅读 legado 的代码文档中发现了这份比较简单明了的正则表达式介绍。

涵盖了正则的大部分常见用法,看目前论坛还没有正则相关教程的帖子,因此转载分享一下。

原文链接:
https://github.com/gedoor/legado ... s/help/regexHelp.md



1. 基本匹配
正则表达式只是我们用于在文本中检索字母和数字的模式。例如正则表达式 cat,表示: 字母 c 后面跟着一个字母 a,再后面跟着一个字母 t。

"cat" 匹配: The cat sat on the mat.

正则表达式 123 会匹配字符串 "123"。通过将正则表达式中的每个字符逐个与要匹配的字符串中的每个字符进行比较,来完成正则匹配。 正则表达式通常区分大小写,因此正则表达式 Cat 与字符串 "cat" 不匹配。

"Cat" 匹配: The cat sat on the Cat



2. 元字符
元字符是正则表达式的基本组成元素。元字符在这里跟它通常表达的意思不一样,而是以某种特殊的含义去解释。有些元字符写在方括号内的时候有特殊含义。 元字符如下:
元字符
描述
.
匹配除换行符以外的任意字符。
[ ]
字符类,匹配方括号中包含的任意字符。
[^ ]
否定字符类。匹配方括号中不包含的任意字符
*
匹配前面的子表达式零次或多次(等价于{0,})
+
匹配前面的子表达式一次或多次(等价于{1,})
?
匹配前面的子表达式零次或一次(等价于{0,1}),或指明一个非贪婪限定符。
{n,m}
花括号,匹配前面字符至少 n 次,但是不超过 m 次。
(xyz)
字符组,按照确切的顺序匹配字符xyz。
|
分支结构,匹配符号之前的字符或后面的字符。
\
转义符,它可以还原元字符原来的含义,允许你匹配保留字符 [ ] ( ) { } . * + ? ^ $ \ |
^
匹配行的开始
$
匹配行的结束

如果你的搜索表达式中包含元字符,必须通过转义才能还原该字符原本的含义。
例如字符串是:abcdef,搜索表达式是:abc,这时显然能匹配到 abc 这个部分。
但如果字符串是:I have $100,搜索的表达式是:$100,那将匹配不到任何内容,因为 $ 这个字符就在上面的“元字符表”中,
如果你想搜出 $100,则必须在该元字符前加一个 \ 进行转义,应该要变成:\$100,才可以实现正确匹配。
其他元字符也是一样,只要你的搜索内容中含有上面“元字符表”中的任意一个字符,都必须在那些元字符前面加上 \ 进行转义。
例如: \? \. \$ 等(如果是包含 \,那就得写成 \\ 才行)。


字符看着挺多,实际不多,随便编了几句话帮助记忆:

  • 一点开头到结尾【.^-$】( - 在 [] 中如果不是表示范围的时候,需要转义
  • 三种括号三重复【()[]{}?+*】
  • 竖起直杠反斜杠【|\】

基本只要理解了三种括号分别起什么作用,?+* 分别代表重复几次,很多正则都能自己编写了(尤其是 () 这个括号实现的“分组替换”,这篇文档里没有实例,建议另外搜索一下,如果知道怎么利用分组,进行部分模式的匹配和替换,相信能提升一大截效率)。
稍微比较特殊的就是 [] 里的 ^ 号代表否定不包含,? 可用于指定懒惰(非贪婪)匹配。

2.1 英文句号
英文句号 . 是元字符的最简单的例子。元字符 . 可以匹配任意单个字符。它不会匹配换行符和新行的字符。例如正则表达式 .ar,表示: 任意字符后面跟着一个字母 a, 再后面跟着一个字母 r。

".ar" 匹配: The car parked in the garage.

2.2 字符集
字符集也称为字符类。方括号被用于指定字符集。使用字符集内的连字符来指定字符范围。方括号内的字符范围的顺序并不重要。 例如正则表达式 [Tt]he,表示: 大写 T 或小写 t ,后跟字母 h,再后跟字母 e。

"[Tt]he" 匹配: The car parked in the garage.

然而,字符集中的英文句号表示它字面的含义。正则表达式 ar[.],表示小写字母 a,后面跟着一个字母 r,再后面跟着一个英文句号 . 字符。

"ar[.]" 匹配: A garage is a good place to park a car.

2.2.1 否定字符集
一般来说插入字符 ^ 表示一个字符串的开始,但是当它在方括号内出现时,它会取消字符集。例如正则表达式 [^c]ar,表示: 除了字母 c 以外的任意字符,后面跟着字符 a, 再后面跟着一个字母 r。

"[^c]ar" 匹配: The car parked in the garage.

2.3 重复
以下元字符 +,* 或 ? 用于指定子模式可以出现多少次。这些元字符在不同情况下的作用不同。

2.3.1 星号
该符号 * 表示匹配上一个匹配规则的零次或多次。正则表达式 a* 表示小写字母 a 可以重复零次或者多次。但是它如果出现在字符集或者字符类之后,它表示整个字符集的重复。 例如正则表达式 [a-z]*,表示: 一行中可以包含任意数量的小写字母。

"[a-z]*" 匹配: The car parked in the garage #21.

该 * 符号可以与元符号 . 用在一起,用来匹配任意字符串 .*。该 * 符号可以与空格符 \s 一起使用,用来匹配一串空格字符。 例如正则表达式 \s*cat\s*,表示: 零个或多个空格,后面跟小写字母 c,再后面跟小写字母 a,再再后面跟小写字母 t,后面再跟零个或多个空格。

"\scat\s" 匹配: The fat cat sat on the cat.

2.3.2 加号
该符号 + 匹配上一个字符的一次或多次。例如正则表达式 c.+t,表示: 一个小写字母 c,后跟任意数量的字符,后跟小写字母 t。

"c.+t" 匹配: The fat cat sat on the mat.

2.3.3 问号
在正则表达式中,元字符 ? 用来表示前一个字符是可选的。该符号匹配前一个字符的零次或一次。 例如正则表达式 [T]?he,表示: 可选的大写字母 T,后面跟小写字母 h,后跟小写字母 e。

"[T]he" 匹配: The car is parked in the garage.

"[T]?he" 匹配: The car is parked in the garage.
  
2.4 花括号
在正则表达式中花括号(也被称为量词 ?)用于指定字符或一组字符可以重复的次数。例如正则表达式 [0-9]{2,3},表示: 匹配至少2位数字但不超过3位(0到9范围内的字符)。

"[0-9]{2,3}" 匹配: The number was 9.9997 but we rounded it off to 10.0.

我们可以省略第二个数字。例如正则表达式 [0-9]{2,},表示: 匹配2个或更多个数字。如果我们也删除逗号,则正则表达式 [0-9]{2},表示: 匹配正好为2位数的数字。

"[0-9]{2,}" 匹配: The number was 9.999 but we rounded it off to 10.0.

"[0-9]{2}" 匹配: The number was 9.999 but we rounded it off to 10.0.
  
2.5 字符组
字符组是一组写在圆括号内的子模式 (...)。正如我们在正则表达式中讨论的那样,如果我们把一个量词放在一个字符之后,它会重复前一个字符。 但是,如果我们把量词放在一个字符组之后,它会重复整个字符组。 例如正则表达式 (ab)* 表示匹配零个或多个的字符串 "ab"。我们还可以在字符组中使用元字符 |。例如正则表达式 (c|g|p)ar,表示: 小写字母 c、g 或 p 后面跟字母 a,后跟字母 r。

"(c|g|p)ar" 匹配: The car is parked in the garage.

2.6 分支结构
在正则表达式中垂直条 | 用来定义分支结构,分支结构就像多个表达式之间的条件。现在你可能认为这个字符集和分支结构的工作方式一样。 但是字符集和分支结构巨大的区别是字符集只在字符级别上有作用,然而分支结构在表达式级别上依然可以使用。 例如正则表达式 (T|t)he|car,表示: 大写字母 T 或小写字母 t,后面跟小写字母 h,后跟小写字母 e 或小写字母 c,后跟小写字母 a,后跟小写字母 r。

"(T|t)he|car" 匹配: The car is parked in the garage.

2.7 转义特殊字符
正则表达式中使用反斜杠 \ 来转义下一个字符。这将允许你使用保留字符来作为匹配字符 { } [ ] / \ + * . $ ^ | ?。在特殊字符前面加 \,就可以使用它来做匹配字符。 例如正则表达式 . 是用来匹配除了换行符以外的任意字符。现在要在输入字符串中匹配 . 字符,正则表达式 (f|c|m)at\.?,表示: 小写字母 f、c 或者 m 后跟小写字母 a,后跟小写字母 t,后跟可选的 . 字符。

"(f|c|m)at.?" 匹配: The fat cat sat on the mat.

2.8 定位符
在正则表达式中,为了检查匹配符号是否是起始符号或结尾符号,我们使用定位符。 定位符有两种类型: 第一种类型是 ^ 检查匹配字符是否是起始字符,第二种类型是 $,它检查匹配字符是否是输入字符串的最后一个字符。

2.8.1 插入符号
插入符号 ^ 符号用于检查匹配字符是否是输入字符串的第一个字符。如果我们使用正则表达式 ^a (如果a是起始符号)匹配字符串 abc,它会匹配到 a。 但是如果我们使用正则表达式 ^b,它是匹配不到任何东西的,因为在字符串 abc 中 "b" 不是起始字符。 让我们来看看另一个正则表达式 ^(T|t)he,这表示: 大写字母 T 或小写字母 t 是输入字符串的起始符号,后面跟着小写字母 h,后跟小写字母 e。

"(T|t)he" 匹配: The car is parked in the garage.
  
2.8.2 美元符号
美元 $ 符号用于检查匹配字符是否是输入字符串的最后一个字符。例如正则表达式 (at\.)$,表示: 小写字母 a,后跟小写字母 t,后跟一个 . 字符,且这个匹配器必须是字符串的结尾。

"(at\.)" 匹配: The fat cat. sat. on the mat.

"(at\.)$" 匹配: The fat cat sat on the mat.



3. 常用字符集
正则表达式为常用的字符集和常用的正则表达式提供了简写。常用字符集如下:
写法
描述
.
匹配除换行符以外的任意字符
\w
匹配所有字母和数字的字符: [a-zA-Z0-9_]
\W
匹配非字母和数字的字符: [^\w]
\d
匹配数字: [0-9]
\D
匹配非数字: [^\d]
\s
匹配空格符: [\t\n\f\r\p{Z}]
\S
匹配非空格符: [^\s]
\n
匹配每行结尾的 <换行>
\r\n
匹配 windows 下每行结尾的 <回车>+<换行>
\r
匹配 mac 下每行结尾的 <回车>



4. 断言
后行断言和先行断言有时候被称为断言,它们是特殊类型的 非捕获组 (用于匹配模式,但不包括在匹配列表中)。当我们在一种特定模式之前或者之后有这种模式时,会优先使用断言。 例如我们想获取输入字符串 $4.44 and $10.88 中带有前缀 $ 的所有数字。我们可以使用这个正则表达式 (?<=\$)[0-9\.]*,表示: 获取包含 . 字符且前缀为 $ 的所有数字。 以下是正则表达式中使用的断言:
符号
描述
?=
正向先行断言
?!
负向先行断言
?<=
正向后行断言
?<!
负向后行断言

4.1 正向先行断言
正向先行断言认为第一部分的表达式必须是先行断言表达式。返回的匹配结果仅包含与第一部分表达式匹配的文本。 要在一个括号内定义一个正向先行断言,在括号中问号和等号是这样使用的 (?=...)。先行断言表达式写在括号中的等号后面。 例如正则表达式 (T|t)he(?=\sfat),表示: 匹配大写字母 T 或小写字母 t,后面跟字母 h,后跟字母 e。 在括号中,我们定义了正向先行断言,它会引导正则表达式引擎匹配 The 或 the 后面跟着 fat。

"(T|t)he(?=\sfat)" 匹配: The fat cat sat on the mat.

4.2 负向先行断言
当我们需要从输入字符串中获取不匹配表达式的内容时,使用负向先行断言。负向先行断言的定义跟我们定义的正向先行断言一样, 唯一的区别是不是等号 =,我们使用否定符号 !,例如 (?!...)。 我们来看看下面的正则表达式 (T|t)he(?!\sfat),表示: 从输入字符串中获取全部 The 或者 the 且不匹配 fat 前面加上一个空格字符。

"(T|t)he(?!\sfat)" 匹配: The fat cat sat on the mat.

4.3 正向后行断言
正向后行断言是用于获取在特定模式之前的所有匹配内容。正向后行断言表示为 (?<=...)。例如正则表达式 (?<=(T|t)he\s)(fat|mat),表示: 从输入字符串中获取在单词 The 或 the 之后的所有 fat 和 mat 单词。

"(?<=(T|t)he\s)(fat|mat)" 匹配: The fat cat sat on the mat

4.4 负向后行断言
负向后行断言是用于获取不在特定模式之前的所有匹配的内容。负向后行断言表示为 (?<!...)。例如正则表达式 (?<!(T|t)he\s)(cat),表示: 在输入字符中获取所有不在 The 或 the 之后的所有单词 cat。

"(?<!(T|t)he\s)(cat)" 匹配: The cat sat on cat</a>.



5. 标记
标记也称为修饰符,因为它会修改正则表达式的输出。这些标志可以以任意顺序或组合使用,并且是正则表达式的一部分。
标记
描述
i
不区分大小写: 将匹配设置为不区分大小写。
g
全局搜索: 搜索整个输入字符串中的所有匹配。
m
多行匹配: 会匹配输入字符串每一行。



6.常见常用正则表达式(自己加了一点)
  • 数字: \d+$
  • 用户名: ^[\w\d_.]{4,16}$
  • 字母数字字符: ^[a-zA-Z0-9]*$
  • 带空格的字母数字字符: ^[a-zA-Z0-9 ]*$
  • 文本中的空行: ^[  \t]*$\n
  • 小写字母: [a-z]+$
  • 大写字母: [A-Z]+$
  • 网址: ^(((http|https|ftp):\/\/)?([[a-zA-Z0-9]\-\.])+(\.)([[a-zA-Z0-9]]){2,4}([[a-zA-Z0-9]\/+=%&_\.~?\-]*))*$
  • 日期 (MM/DD/YYYY): ^(0?[1-9]|1[012])[- /.](0?[1-9]|[12][0-9]|3[01])[- /.](19|20)?[0-9]{2}$
  • 日期 (YYYY/MM/DD): ^(19|20)?[0-9]{2}[- /.](0?[1-9]|1[012])[- /.](0?[1-9]|[12][0-9]|3[01])$
  • 求更求转发致谢: [\((【].*?[求更谢乐发推].*?[】)\)]
  • 查找最新章节: 您可以.*?查找最新章节
  • ps/PS: (?i)ps\b.*
  • Html标签: <[^>]+?>
  • 匹配 html 标签中的特定字符(如标点):,(?=[^<>]*<\/p>) (这个示例是查找 p 标签中的所有逗号,正向断言的使用范例)
  • 包含某字符的字符串:^(?=.*有).*(包含“有”字)
  • 不包含某字符的字符串:^(?!.*有).*(不包含“有”字),或也可写成 ^[^有]*$
  • 匹配中文字符:[\u4e00-\u9fff],或者也有写成 [\u4e00-\u9fa5] 的
  • 匹配 emoji:[\u{1F601}-\u{1F64F}\u{2702}-\u{27B0}\u{1F680}-\u{1F6C0}\u{1F170}-\u{1F251}\u{1F600}-\u{1F636}\u{1F681}-\u{1F6C5}\u{1F30D}-\u{1F567}]
  • 匹配 emoji  的第二种写法,比上面的多匹配了一些:(\ud83c[\udf00-\udfff])|(\ud83d[\udc00-\ude4f\ude80-\udeff])|([\u2600-\u2B55])

扩展阅读:正则表达式案例(重点看 3 楼和 4 楼即可)
扩展阅读:环视(断言)入门案例
扩展阅读:几条标点繁转简的正则




利用正则将 txt 文本的排版转换为校对上传区标准:
统一排版格式为:行首两全角空格,行间无空行,章节间两空行

个人随意写的,可能某些情况下不是很严格,需要开启编辑器中的【正则表达式】搜索替换模式。

1.去除所有空行:
【搜索】^[  \t]*$\n 【替换】为空

2.去除行首行尾空格:
【搜索】^[  \t]+ 【替换】为空
【搜索】[  \t]+$ 【替换】为空


3.所有行首统一增加两个全角空格:
【搜索】^ 【替换】  (两个全角空格不要漏掉)

4.去除章节标题前的全角空格,并在每个章节标题前空两行:
部分编辑器,如 vscode 和 sublime text 中,替换处的分组引用形式为 $1 而非 \1。
章标题的部分可能需要根据实际需求,自己调整一下,例如加上楔子、引子、尾声、感言、番外之类的。
【搜索】^[  \t]*([第卷章][\d一二三四五六七八九十零〇百千万两廿卅卌\.\-]+[章回卷部集节篇]?(?:[  \t::]|$)+) 【替换】\n\n\1

执行完上面几条,再看情况是否需要把文件最开头的两个空行去掉,然后就完事了。

评分

参与人数 2威望 +2 铜币 +30 收起 理由
pvps + 20 论坛有您更精彩!
baizhai1704 + 2 + 10 论坛有您更精彩!

查看全部评分

回复

使用道具 举报

16

听众

0

收听

13

好友

贡士

Rank: 7Rank: 7Rank: 7

UID
155378
积分
2986
回帖
1024
主题
67
铜币
44306
威望
2435
银币
0
贡献
0
发书数
57
注册时间
2023-6-14
最后登录
2024-4-28
在线时间
1538 小时
 楼主| 发表于 2023-11-18 12:44 | 显示全部楼层
本帖最后由 edennow 于 2024-2-20 11:07 编辑

【一个较为复杂的正则示例】

文本内容:
正文 1(注:我是注释1(我是注释1-1)我是注释1.1(我是注释1.1-1))正文 2(注:我是注释2)正文 3(注:我是注释3(我是注释3-1))

这段文本内容中使用了多层括号来进行行内的注释,如果想匹配到如下的完整注释怎么办呢?
正文 1(注:我是注释1(我是注释1-1)我是注释1.1(我是注释1.1-1)正文 2(注:我是注释2)正文 3(注:我是注释3(我是注释3-1))

如果单纯写(注:.*) 或者(注:.*?)显然无法实现正确匹配。

贴一下 sigil 贴吧中【注释处理插件】的【行内注释转多看注释】匹配正则,
相当有效,不过为了提高通用性,写得比较复杂,基本可以处理各种括号嵌套形式的行内注释,供参考:
((?:(?:<sup>)?※(?:</sup>)?)(.*?))?[(\(]([^()\(\)]{0,5}[註注][释釋]?(?:[\d]+)?[::︰\s ])((?:[^\(\)()]|[(\(](?:[^\(\)()])*[)\)])*)[\))]

试分段分析如下:
1.((?:(?:<sup>)?※(?:</sup>)?)(.*?))? 这部分匹配带 ※ 的注标在前的情况,好像比较少见这种形式,可以先忽略不管。

2.[(\(]([^()\(\)]{0,5}[註注][释釋]?(?:[\d]+)?[::︰\s ]) 这部分匹配行内注释的开始部分,
“注”字前面最多允许有五个其他字符,如:(注 (译者注 (译注 (原注 (注释 (原注释 等。
其中的 (?:[\d]+)?[::︰\s ]) 匹配注释序号(可没有)和冒号(或空格等标识符),例如:(注: (注1: (译注1:等;

3.((?:[^\(\)()]|[(\(](?:[^\(\)()])*[)\)])*) 这部分可匹配多重括号嵌套的内容(最多两层,再多一层也无法匹配,如果非要多加层次,可能只能引入递归写法,但一般不建议搞得太复杂)。
其中:
[^\(\)()]|[(\(] 匹配非括号字符、左开口括号。
(?:[^\(\)()])* 匹配非括号连续内容。
[)\)] 匹配右闭合括号。
把以上 ①②③ 部分联立,重复 0 到多次。

以上面的【注释1】为例,匹配顺序如下:
我是注释1(
我是注释1(我是注释1-1
我是注释1(我是注释1-1)
我是注释1(我是注释1-1)
我是注释1.1(
我是注释1(我是注释1-1)我是注释1.1(我是注释1.1-1
我是注释1(我是注释1-1)
我是注释1.1(我是注释1.1-1

最后再跟上另外一个 [\))] 右闭合括号,限定单条注释内容的结尾。
回复 支持 反对

使用道具 举报

4

听众

0

收听

0

好友

秀才

Rank: 5Rank: 5

UID
150225
积分
544
回帖
1083
主题
1
铜币
53
威望
2
银币
0
贡献
0
发书数
0
注册时间
2023-2-16
最后登录
2024-4-28
在线时间
376 小时
发表于 2023-11-23 11:53 | 显示全部楼层
谢谢分享,学习学习!
[发帖际遇]: 西元3000年,身为考古学家的 兵河之眼,从起点的服务器里面考证到古人类的强大程度,获得奖励 2 威望. 幸运榜 / 衰神榜
回复 支持 反对

使用道具 举报

4

听众

0

收听

0

好友

秀才

Rank: 5Rank: 5

UID
162249
积分
836
回帖
1163
主题
15
铜币
505
威望
246
银币
0
贡献
0
发书数
12
注册时间
2023-9-21
最后登录
2024-4-24
在线时间
254 小时
发表于 2024-2-5 16:42 本帖来自阡陌居手机频道 | 显示全部楼层
感谢楼主分享知识经验,应该收藏学习
回复 支持 反对

使用道具 举报

7

听众

4

收听

2

好友

举人

Rank: 6Rank: 6

UID
141223
积分
1305
回帖
1149
主题
1
铜币
4385
威望
730
银币
0
贡献
0
发书数
0
注册时间
2022-3-8
最后登录
2024-4-28
在线时间
515 小时
发表于 2024-3-7 01:03 | 显示全部楼层
感谢楼主分享~~努力学习中!!
人活世间,有所为有所不为。
回复 支持 反对

使用道具 举报

7

听众

0

收听

1

好友

贡士

Rank: 7Rank: 7Rank: 7

UID
143261
积分
2138
回帖
1898
主题
29
铜币
16386
威望
1168
银币
1
贡献
3
发书数
0
注册时间
2022-5-28
最后登录
2024-4-28
在线时间
594 小时
发表于 2024-4-14 13:29 | 显示全部楼层
不错,论坛提供的排版脚本功能有限,最佳方法还是自己学一下正则表达式,排版时能节省大量时间
[发帖际遇]: dot 认真洗了个脸,竟获得“女儿国十大美男”称号,奖励 4 铜币. 幸运榜 / 衰神榜
回复 支持 反对

使用道具 举报

1

听众

0

收听

0

好友

伴读

Rank: 2

UID
172771
积分
28
回帖
38
主题
1
铜币
120
威望
8
银币
0
贡献
0
发书数
0
注册时间
2024-3-24
最后登录
2024-4-28
在线时间
17 小时
发表于 2024-4-15 09:23 | 显示全部楼层
感谢楼主分享的正则表达式,在找一份简明扼要的教程
回复 支持 反对

使用道具 举报

1

听众

0

收听

0

好友

儒士

Rank: 4

UID
170193
积分
259
回帖
392
主题
1
铜币
291
威望
62
银币
0
贡献
0
发书数
0
注册时间
2024-2-19
最后登录
2024-4-28
在线时间
53 小时
发表于 2024-4-15 16:05 | 显示全部楼层
这个APP挺不错的,开源代码可以好好学习下
正则表达式,在写代码、在WPS(WORD)批量替换修改时,都很有用
[发帖际遇]: txfantong 在孤儿院做义工,奖励 3 铜币 幸运榜 / 衰神榜
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|阡陌居

GMT+8, 2024-4-28 18:18 , Processed in 0.040974 second(s), 26 queries .

Powered by Discuz! X3.4

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表