概述
学习了正则表达式之后一定要练习才有用。
Regex Golf是一个很有用的正则表达式练习网站。
注:练习其实只做前十道题就可以了,后面的很难涉及的正则表达式知识很深,平时也用不到那么深的,而且也没有那种必要,遇到了也不需要用正则表达式来解决自然有更优更简单的解决方式。
Warmup
Type a regex in the box.
答案:foo
解释:我们观察"Match all of these…"下面的所有字符串都有foo
这三个连续字符,所以只需要输入foo
就可以匹配"Match all of these…"下的所有字符串,而不匹配"and none of these…"下的所有字符串,当然为了能够完全匹配"Match all of these…"下的所有字符串,正则表达式应该写成这样:.*foo.*
,就能匹配foo
前面和后面出现的字符了。
Anchors
You are deducted one point per character you use, and ten if you match something you shouldn’t.
答案:ick$
或ck$
或k$
或.*ick$
解释:观察"Matcch all of these…"下的所有字符串可以发现都有"ick"三个字符,并且都是以它们结尾的,在正则表达式中可以使用$
符号来表示结尾,所以答案是ick$
,当然也可以表示成以k$
结尾。
It never ends
$ not allowed
答案:fu\b
或.*fu\b
或fu(?!\w)
解释:题目要求不能使用$
符号结尾,但在正则表达式中还提供了\b
字符来匹配一个单词边界。并且"Match all of these…"下的所有字符串中都包含fu
字符串。还可以使用断言的方式fu(?!\w)
来实现,即不允许fu
后面有字符。
Ranges
The test vectors were generated by grepping /usr/dict/words. Can you tell?
答案:[abcdef]{4,}
解释:我们观察"Match all of these…"下的所有字符串中的字符都是abcdef
中的字符组成的,所以使用[abcdef]
来表示"abcdef"中的任意一个字符,而每个单词中的字符出现次数大于等于4,所以使用{4,}
来表示字符个数大于等于4。
Backrefs
This doesn’t really work as a tutorial. Not really clear what you’re supposed to do here.
答案:(.{3}).*\1
解释:我们观察"Match all of these…"下的所有字符串,发现所有的字符串都存在三个字符重复的情况,如"allochirally"中"all"重复了两次,"anticovenanting"中"ant"重复了两次,"barbary"中"bar"重复了两次。而.{3}
表示任意字符出现三次,而(.{3})
将其分组,而重复字符串后面可能还跟着其他字符,所以使用.*
贪婪匹配,而(.{3}).*\1
中的\1
反向引用第一个分组中的内容,表示要匹配一模一样的内容,所以(.{3}).*\1
能匹配"Match all of these…"下的所有字符串,而不匹配"and none of these…"下的所有字符串。
Abba
Let’s pretend this one is not a rehash of the last one.
答案:^(?!.*(.)(.)\2\1.*)
解释:我们观察"and none of these…"下的所有字符串,发现存在"abba"结构的子串,如"anallagmatic “中的"alla”、"coccomyces “中的"occo”、"hexacoralla “中的"alla”,而"Match all of these…"中不存在这样结构的字符串。正则表达式(.)(.)\2\1
可以匹配abba
这样结构的字符串,而.*(.)(.)\2\1.*
会匹配abba
结构之前或之后有字符的情况。而(?!.*(.)(.)\2\1.*)
中的(?!pattern)
是一个断言,表示负向先行断言,即该位置之后的字符不能匹配.*(.)(.)\2\1.*
这样结构的正则表达式,而^(pattern)
表示以pattern正则表达式开头,而完整的^(?!.*(.)(.)\2\1.*)
表示以不是"abba"这样结构的字符串开头的字符串。
A man, a plan
You’re allowed to cheat a little. Even in hard mode, words will be no longer than 13 characters.
答案:^((.)(.)(.*)\3\2\1)$
或^(.)(.)(.*).?\3\2\1$
或^(.)(.).*\2\1$
解释:我们观察"Match all of these…“下的所有字符串发现是这样的结构:abccba
或abcba
或abba
。如"civic”、“deedeed”、“degged”、“kook”,至少都有abba
这样的结构,而在ab
和ba
中间存在一个字符串,它们可能是cc
、c
、pap
,因此(.)(.).*\2\1
能匹配这样的结构,但在输入框输入这样的正则表达式后,发现"and none of theses…“下的字符串"camshach”、“psorosperm”、"teleoptile"没有被不匹配,那么我们添加^$
符号规定边界即^(.)(.).*\2\1$
则可以匹配所有的情况。
Prime
答案:^(?!(xx+)\1+$)
解释:略。
Four
You can get an extra point by ignoring the name of this level.
答案:.*(\w)(\w\1){3}.*
或(.)(.\1){3}
解释:我们观察"Match all of these…“下的所有字符串,发现这样的规律:“a-ba-ca-da”,其中"a"是字符串中出现次数最多的一个字符,而”-“号只是为了便于分析规律没有实际意义,而"b”、“c”、“d"只是"a"字符前面的任意字符的代称,如"Makaraka"中的"a-ka-ra-ka”、“degenerescence"中的"e-ge-ne-re”、“elevener"中的"e-le-ve-ne”、“locomotory"中的"o-co-mo-to”,因此我们写出这样的正则表达式(.)(.\1){3}
,其中第一个(.)
代表出现次数最多的字符如"a"等,而(.\1)
重复第一个分组中的内容,并且前面的.
可以是任意字符,如第一个分组中的字符是"a"则可以匹配"ka"、“ra”,如第一个分组中的字符是"e"则可以匹配"ge"、“ne”、"re"这样的,而{3}
表示前面的(.\1
)重复三次。
Order
Cheat.
答案:^.{5}[^e]?$
解释:题目要求字符串中的字符按照字母顺序排列,比如"access"中的"c"字符在"a"字符的字母顺序之后、"e"字符在"c"字符和"a"字符之后,而"analyse"中的第二个"a"字符在"n"字符之后,是违反字母顺序的,所以不应该被匹配。而答案是取巧了,并没有对字母顺序进行规定,而是根据字母个数取巧写的正则表达式,即"Match all of these…"下的所有字符串的长度都是5到6,而"and none of these…"下的字符串除了"oriole"长度为6之外其他都大于6,所以进行了限制,并且"oriole"字符串是以"e"字符结尾的。