2023年政策修订增补工作正在进行中,欢迎参与!
  • Moegirl.ICU:萌娘百科流亡社群 581077156(QQ),欢迎对萌娘百科运营感到失望的编辑者加入
  • Moegirl.ICU:账号认领正在试运行,有意者请参照账号认领流程

User:東東君/正则表达式

萌娘百科,万物皆可萌的百科全书!转载请标注来源页面的网页链接,并声明引自萌娘百科。内容不可商用。
跳转到导航 跳转到搜索

简介

正则表达式(英语:Regular Expression,在代码中常简写为regex、regexp或RE),是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。在很多文本编辑器里及程序中,正则表达式通常被用来检索、替换那些匹配某个模式的文本。

wikitext语法中没有“数据类型”这一概念,我们可以认为其中的所有数据都是字符串(string)类型的[来源请求],因此正则表达式可以在wikitext中发挥极大的作用。

因为萌百中对于正则匹配的支持主要基于Lua语言所提供的string库,string库的正则表达式实现并未遵照POSIX规范,在使用上会与普通的正则表达式有所不同,这里着重讲解Lua的正则表达式写法,若你有正则表达式的基础,也可以先看这里→Lua正则与标准正则的不同

语法对照表

Lua中的正则表达式 正则表达式由元字符按照规则(语法)组成。lua中的特殊字符是% . [ ] ( ) ^ $ * + - ?,一共12个。它们和一般字符按规则构成了lua的正则表达式。

建议先阅读一遍该表,再结合下面的例子进行理解。

元字符 描述 表达式示例 完整的匹配字符串
字符
普通字符 除去%.[]()^$*+-?的字符,匹配字符本身 string string
. 匹配任意字符 str.ng string
% 转义字符,改变后一个字符的原有意思。当后面的接的是特殊字符时,将还原特殊字符的原意。%和一些特定的字母组合构成了lua的预定义字符集。%和数字1~9组合表示之前捕获的分组 strin%a string
[...] 字符集(字符类)。匹配一个包含于集合内的字符。[...]中的特殊字符将还原其原意,但有下面几种特殊情况
1. %],%-,%^作为整体表示字符']','-','^'
2. 预定义字符集作为一个整体表示对应字符集
3. 当]位于序列的第一个字符时只表示字符']'
4. 形如[^...],[...-...]有特定的其他含义
strin[a-z] string
* 表示前一个字符出现0次或多次 s* sssss
+ 表示前一个字符出现1次或1次以上 s+tring ssstring
- 表示前一个字符出现0次或多次,且将尽可能匹配较少的内容 s-tring tring
? 表示前一个字符出现0次或1次 strin?g strig
预定义字符集
%s 空白字符[ \r\n\t\v\f](半角空格、全角空格、换行) str%sing str ing
%p 半角标点符号 str%ping str,ing
%c 控制字符
%w 字母数字,相当于[a-zA-Z0-9] %w%w%w st0
%a 字母a到z和A-Z,相当于[a-zA-Z] %a%a%a str
%l 小写字母,相当于[a-z] %l%l%l str
%u 大写字母,相当于[A-Z] %u%u%u STR
%d 数字,相当于[0-9] %d%d%d 123
%x 16进制数,相当于[0-9a-fA-F] %x%x%x 59c
%z ascii码是0的字符
捕获组
(...) 表达式中用小括号包围的子字符串为一个分组,分组从左到右(以左括号的位置),组序号从1开始递增。
捕获组不会对匹配结果产生任何影响,只是用来在匹配后对匹配结果进行其他操作的
(string) string
边界匹配
^ 匹配字符串开头 ^string string
$ 匹配字符串结尾 string$ string
平衡匹配
%bxy 平衡匹配(匹配xy对)。这里的x,y可以是任何字符,即使是特殊字符也是原来的含义,匹配到的子串以x开始,以y结束,并且如果从x开始,每遇到x,计算+1,遇到y计数-1,则结束的y是第一个y使得计数等于0。就是匹配成对的符号,常见的如%b()匹配成对的括号 %b{} {string}

示例

在这里我们使用用途最为广泛的replace(替换匹配)进行演示。

{{#invoke:String|replace
|source= <!-- 要匹配的字符串 -->
|pattern= <!-- 正则表达式 -->
|replace= <!-- 要替换的内容 -->
|count= <!-- 替换次数,默认为尽可能地多次匹配 -->
}}

该模板未匹配的部分将原封不动地返回,若整个字符串都不匹配,则全部原样返回。

关于这个模块的更多细节请参考:User:宇文天启/字符串处理#replace

捕获组的使用

{{#invoke:String|replace
|source= 卡布奇诺,咖啡摩卡,咖啡拿铁
|pattern= (卡布奇诺),(咖啡摩卡),(咖啡拿铁)     <!-- 在正则中使用括号作为捕获组的标志,捕获组本身不会对匹配造成任何影响 -->
|replace= %3,%2,%1!魔法少女智乃华丽变身~!   <!-- 在替换栏中,使用%n为替代字符,代表对应的捕获组,从1开始,最多9个。若要输出%元字符,则要写成“%%” -->
|plain=false                                     <!-- 接上↑:其中,“%0”代表匹配到的全部字符。 -->
}}

结果:咖啡拿铁,咖啡摩卡,卡布奇诺!魔法少女智乃华丽变身~!

匹配任意数量的字符

{{#invoke:String|replace
|source= 这是一个超超超超超级厉害的页面!
|pattern= .+超+(.+)                       <!-- 匹配到了整句 -->
|replace= %1                              <!-- 将匹配到的内容替换为第一个捕获组的内容 -->
|plain=false
}}

结果:级厉害的页面!

{{#invoke:String|replace
|source= goooooogle
|pattern= %l([^g]*)gle               <!-- 这里表示[^g]匹配非g的字符 -->
|replace= %1
|plain=false
}}

结果:oooooo

匹配任意位置的字符

{{#invoke:String|replace
|source= 《你好,世界!》123《你好,世界!》
|pattern= 《你好,世界!》(123)$           <!-- 这将原封不动地返回,因为匹配的字符串的末尾不是123 -->
|replace= %1
|plain=false
}}

结果:《你好,世界!》123《你好,世界!》

{{#invoke:String|replace
|source= <123>456<123><123>456<123><123>456<123><123>456<123>
|pattern= (<123>456<123>)<123>456<123>$                   <!-- 取倒数第二组“<123>456<123>” -->
|replace= 【%1】<123>456<123>
|plain=false
}}

结果:<123>456<123><123>456<123>【<123>456<123>】<123>456<123>

{{#invoke:String|replace
|source= 王木匠饭还没吃完,就径直向工场走去,满脑子想的都是今天早上刚到的木料。别看就是个锯木头的,一块好木,在巧匠手里就像是块璞玉...
|pattern= (径直向).+(走去)      <!-- 有时为了更精确地匹配某个地方,就需要在两边添加许多原文有的,或者可预见的信息,帮助定位 -->
|replace= %1家%2
|plain=false
}}

结果:王木匠饭还没吃完,就径直向家走去,满脑子想的都是今天早上刚到的木料。别看就是个锯木头的,一块好木,在巧匠手里就像是块璞玉...

转义的使用

{{#invoke:String|replace
|source= 平常的流浪者大叔(60岁),昨天给我发邮件说喜欢[汚れ]的小哥(45岁),我(53岁)
|pattern= .+(%[汚れ%]的小哥%(45岁%)).+                <!-- 原文包含“[ ] ( )”等语法使用的符号,需要使用%转义为普通符号,防止被作为语法解析 -->
|replace= %1
|plain=false
}}

结果:[汚れ]的小哥(45岁)

贪婪模式与非贪婪模式

{{#invoke:String|replace
|source=  a123a a456a a456a bbbbbbbbbbbbbb
|pattern= (a.+a).*                 <!-- 默认为贪婪模式,这将匹配直到文本最后的a的字符串 -->
|replace= %1
|plain=false
}}

结果:a123a a456a a456a

{{#invoke:String|replace
|source=  a123a a456a a456a bbbbbbbbbbbbbb
|pattern= (a.-a).*                 <!-- 使用减号的非贪婪模式,只会匹配到第一组 -->
|replace= %1
|plain=false
}}

结果:a123a

平衡匹配

{{#invoke:String|replace
|source= (待添加)实在是太萌了
|pattern= %b()
|replace= 智乃酱
|plain=false
}}

结果:智乃酱实在是太萌了

应用模板

请参考:User:宇文天启/字符串处理

  • {{REesc}} 这个模板将对字符串内的所有语法符号进行转义,经常用于模板输入的参数要加入正则表达式时,进行转义操作,防止被错误解析为正则语法。

Lua正则与标准正则的不同

  • 除上表列举出特殊字符,其他的均无效(如:%r、%t、%w)等。
  • 将特殊字符大写并不代表匹配非该特殊字符的含义,而是会当作普通字符处理。
  • . 代表任意字符,包括\n换行符。
  • char{min,max} 不支持指定字符数量的操作,花括号同样也只是普通字符。
  • (abc|def|) 不支持预料多种结果的操作,若只想判断是否存在,且可预见的情况下可以使用a?b?c?这种形式。
  • 不支持任何零宽断言,如:?= 、 ?<= 、 ?! 、 ?<!