在reddit推薦的文章上看到的。下面的代碼在CMD視窗下運行通過。如果在BASH下面運行,單引號和雙引號要對調。
perl -wle "print 'prime' if (1 x shift) !~ /^1?$|^(11+?)/1+$/" <任意一個數>
Python的代碼是:
import re
def is_prime(num):
return not re.match(r"^1?$|^(11+?)/1+$", "1" * num)
Ruby有Perl的血脈,所以代碼和Perl版本幾乎一樣(其實無所謂,反正關鍵都是同樣一段regex):
ruby -e "puts 'prime' if ('1' * ARGV.shift.to_i) !~ /^1?$|^(11+?)/1+$/" <任意一個數>
判斷方法很有意思。把給出的數用一進位表示。比如5就是11111。然後從2開始一個數一個數地看這段表示中1的數目是否是其中任意一個的數的倍數。比如說當給出的數是4,則對應的表示是1111。那麼1111匹配^11/1,也就是說它匹配^(11+?)/1+$。那麼它是2的倍數。所以4不是質數。而當給出的數是7時,對應的表示是1111111。那這葛字串不能匹配11/1+,也不能匹配111/1+,...,也不能匹配1111111/1+,所以7是質數。
解釋一下regex的構造:
^1?$,匹配空的字串或者"1"。換句話說,0和1不是質數。
(11+?)/1+,(11+?)匹配長度為2或者2以上且形如"11.....111"的字串。注意那個問號,說明匹配點到即止,不是貪婪匹配。這點很重要,不然(11+)可以匹配所有長度大於2且形如"11...1"的字串。回溯參考符/1表示匹配之前匹配到的字串,也就是(11+?)了。點睛之筆來了:/1+表示匹配一到多個之前匹配到的(11+?)。換句話說,匹配長度為N*M的字串,這裡N大於0,而M就是(11+?)匹配上的長度。因為Perl的regex自動回溯,所以(11), (111), (1111)...都會被自動嘗試。
這段代碼除了漂亮精巧值得欣賞,以及可以用來玩味理解regex以外,還有什麼價值呢?效率?顯然不夠高。實用性?恐怕也沒有多少。不過,這段代碼隱含了重要的編程思想:編碼。我們可以把一段問題用某種方式表達出來,再根據這段表達謀求解決之道。這種方法看似簡單,卻應用廣泛。我們可以把各式自動機用字串表示出來,由此相對容易地發現很多深刻的性質。我們把系統規格用狀態機器描述出來,再把狀態機器用邏輯公式表達出來,於是我們可以自動驗證系統規格有沒有邏輯上的缺陷,有沒有安全問題。進一步說,我們賴以為生的整個計算體系也是建立編碼的基礎上:所有的資料所有的命令最終被轉換為0和1表示。計算理論基礎更離不開編碼。從歌德爾定理到圖靈機理論到自動機理論到計算複雜性,不知多少偉大的證明依靠編碼。
還有一點好玩兒的。Perl的regex匹配是NP-Complete的問題。這裡有證明。數獨(sudoku)也是NP-Complete問題。所以我們可以通過寫出regex運算式來解決數獨猜謎。關鍵還是把數獨的題面轉化成可以匹配的字串。牛人Abigail給出了一個方案。Abigail也是上面判斷質數代碼的作者。呵呵,其實我們也可以把regex配備問題轉換成數獨問題,然後用數獨程式來實現匹配。哪位閑得不行的老大可以去試試。