正则表达式(英语: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:宇文天启/字符串处理
.
代表任意字符,包括\n
换行符。char{min,max}
不支持指定字符数量的操作,花括号同样也只是普通字符。(abc|def|)
不支持预料多种结果的操作,若只想判断是否存在,且可预见的情况下可以使用a?b?c?
这种形式。