Regex Golf 正則表達式學習

正則表達式匹配工具
Regex Golf 習題,據說練習通過17題後就能精通正則表達式。
引用自 http://jimliu.net/2014/01/04/regex-golf/
1.Plain String
Type a regex in the box. You get ten points per correct match. Hit Enter to go to the next ‘level’.

送分題,毫無疑問,答案是foo,207分。

2.Anchors
You are deducted one point per character you use, and ten if you match something you shouldn’t.

考察對邊界的應用。最開始我給出的是ick$,後來發現是ck$,最後喪心病狂的發現是k$,得分分別是206, 207, 208。

3.Ranges
The test vectors were generated by grepping /usr/dict/words. Can you tell?

考察對範圍的應用,同時結合邊界和量詞。我的答案是^[a-f]+$,當然^[a-f]*$也是可以的,並且得分一樣,都是202。

4.Backrefs
This doesn’t really work as a tutorial. Not really clear what you’re supposed to do here.

從題面上看,是考察對於反向引用的使用。我給的答案是(.{3,}).\1,得分是199,找了很久沒有發現優化空間,直到我看了牛人解答之後,竟然給出了(...).\1,我真蠢。

階段性小結
毫無疑問前4關是比較簡單的,其中前3關都是正則中會用到的基本用法,第4關只要是比較熟練的同學也肯定是會的,能否拿高分差別在於夠不夠省。

5.Abba
Let’s pretend this one is not a rehash of the last one.

說實話這個題目相當具有迷惑性,也挺有難度,微博上看的確有不少同學卡在這題上了。

觀察題面,要求不匹配字符串內含形如abba組合的串,首先可以簡單地使用反向引用構造出(.)(.)\2\1。

有了它後,怎麼做到不匹配呢?這裏要用到負向前瞻,負向前瞻是零寬斷言的一種,JavaScript中的負向前瞻形如(?!exp),匹配後面不是exp的串。

OK,下面一步步構造,首先用(?!(.)(.)\2\1)試試,發現左邊的都匹配上了,右邊的……也匹配上了- -|。然後用一個很損的辦法,^(?!(.)(.)\2\1),右邊幹掉了2個。

這時候其實回想一下題目,我們要排除的是形如abba的串,那麼在剛纔的基礎上加上^(?!.(.)(.)\2\1.),對了!191分。

再仔細想一下,對abba再後面的串其實沒必要再限制了,優化到^(?!.*(.)(.)\2\1),193分。

JavaScript的正則只支持前瞻(Look Ahead)而不支持後瞻(Look Behind),也就是說我們只能“用右邊的東西限制當前位置”。

6.A man, a plan
You’re allowed to cheat a little, since this one is technically impossible.

對稱串嗯哼?有了前面的經驗這題不會很難的,我構造了半天,中間也經過幾次升級,結果用了(.)(.).?\2\1.?$,得分是175。

牛X答案給的是^(.)[^p].*\1$,我只想說這東西相當牛X,而且很符合題目描述cheat a little,它能拿到177分。

7.Prime
The length is not part of the string. I should probably have chosen a different color.

非常非常好玩的一道題,要不是我曾經看過M67的一篇博客知道正則有判斷素數這種神奇的用法,這道題簡直無從下手。

首先用^x?$|^(xx+?)\1+$判斷長度是合數,因爲沒有長爲0或1的,所以直接精簡到^(xx+?)\1+$,nice!錯誤答案全部匹配,正確答案全部不匹配。

有了上面的經驗,剩下的不會有什麼難度了,^(?!(xx+?)\1+$),285分到手。而牛人答案^(?!(..+)\1+$)中卻沒有對中間的xx+?啓用非貪婪,達到286分,這個因爲我不怎麼看得懂這個素數匹配的原理,所以我也不再妄加評判了……

8.Four
You can get an extra point by ignoring the name of this level.

觀察題面,它要匹配的其實是形如aaaa或者是aaaa,按照這個思路,可以構造出.(.)(?:.\1){3,}|(.).(?:\2.){3,},這樣已經可以拿到179分了。

其實進一步觀察,不難發現其實形態1中的開頭和形態2中的結尾是並不重要的,所以我們想要的其實只是aaa而已,那麼(.)(.\1){3}就可以完美解決了,並且能夠得到199分。

階段性小結
5~8題開始有點沒節操了,但至少還是在技術技巧的範圍內的,第7題天馬行空,報酬也豐厚。

事實上我從9題開始就胡謅了。

9.Order
Cheat.

描述一點也不含蓄,看題面,發現需要匹配的是非降序的串。

然後我實在是不會了,我本來天真的以爲(.)[\1-z]中的範圍表達式是可以利用反向引用的,結果當然是不行。於是我隨便寫了個^a[b-z]+$,慘淡地得了41分。

然後看了牛人解答我哭了,^.{5}[^e]?$,果然是cheat,當然也不得不佩服這觀察力,199分。

10.Triples
Multiples of 7 are left as an exercise for the reader.

題面很簡單,就是能被3整除。搜索了一下,有能構造匹配能被3整除的2進制數的辦法,但是這裏是10進制。於是胡謅繼續,00就這麼搞上去,也能118分你敢信?

答案是00($|3|6|9|12|15)|4.2|.1.+4|55|.17,滿分達到了596分。我覺着這貨跟數學沒啥關係,就是靠觀察力硬湊……

11.Glob
題面非常有意思,要構造一個xxx matches yyy這種,也就是matches的前面充當正則的時候能匹配後面的串。

當然如果往這個方向想,那就肯定做不出來的(好殘酷),當我看到答案的時候,我嚇尿了:ai|c$|^p|[bcnrw][bnopr]這要有多強大的觀察力才能做出來。

我的答案*,58分慘淡收場。

12.Balance
This one is also impossible, but there’s a finite number of test cases.

描述都說impossible,當場嚇尿。你猜我給的是什麼?說出來嚇死你:^$,得分8也嚇死你……

@Thomas憑藉<<<<得到了146分,我佩服他想象力!

牛人答案是^(<(<(<(..)>)>)>)$得分288,但這依然並不是完美答案。

括號配對對於正則是一個非常大的難題,因爲正則文法的定義先天就不是遞歸的。我們現在用的加強的正則表達式,儘管加入了反向引用、計數、前瞻後瞻等高級功能,但我理解它的數學定義並沒有超過這個範疇,而是在實現引擎層面上新增的功能。

但其實正則來處理括號配對不是不可能的,C#標準庫的正則是支持平衡組的,我也沒有實際用過,就不深入聊這個了。

階段性小結
9~12題是相當喪心病狂,不“作弊”基本沒法正常做了。而且後面的題目作者好像已經完全懶得寫描述了。

13.Powers
從題目名字看,就是冪(我不是要說楊冪)。

付出了把鍵盤敲爛的代價,我喪心病狂地寫出了^((((((((((x)\10?)\9?)\8?)\7?)\6?)\5?)\4?)\3?)\2?)\1?$,雖然是完美匹配,但估計是因爲表達式太長,只得了56分。

牛人答案是^(?!(.(..)+)\1*$),這個很有意思,我們來解讀一下。

首先我只看到了正確答案是長度爲2的整數次冪的串,而沒有觀察錯誤答案,這不得不說是一個重大失誤!

錯誤答案中比較短的幾個,長度是3,5,7,11,13的串,可以表示爲2n+1,那麼可以先構造出^(.(xx)+)$,發現還匹配了401和1025。

那麼,長度爲28,48,160,600的呢?把他們做因數分解,發現28=722, 48=32222, 160=522222, 600=75222,也就是說他們都是(2n+1)pow(2, m)的形態。於是在上面的基礎上構造出來^(.(xx)+)\1$,能夠成功匹配所有錯誤答案了!

結合第7題中的狗血方法,稍作修改就得到^(?!(.(..)+)\1*$)這個答案,其實也不過才93分而已嘛……當然不看答案的話我也真心找不到這規律。

14.Long Count
我會告訴你我直接把左邊的那串數字拿來用了嗎?191分。

答案是^((.+)0 \2+1 ?)*$仔細看看應該能明白,還是憑藉細心的觀察,這樣可以拿到253分。

15.Long Count v2
我會告訴你我又直接把左邊的那串數字拿來用了嗎?191分。

答案又是^((.+)0 \2+1 ?)*$,這樣又可以拿到253分。我根本沒觀察跟14題有啥區別,所以不評論了。

16.Alphabetical
毫無頭緒的一題,aerate騙到33分,好累,感覺不會再愛了。

答案是.r.{32}r|a.{10}te|n.n..,317分,我的建議是不要試圖解讀它。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章