[奇淫怪巧] 利用正則表達式判斷素數


最近在學習正則表達式,偶然間看到利用正則表達式判斷一個數是不是素數的帖子。當時就震驚了,覺得好神奇。那個判斷素數的函數是這樣子的:

public static bool IsPrime(int i)
{
    return !Regex.IsMatch(new String('*', i), "^.?$|^(..+?)\\1+$");
}

有沒有覺得很神奇?我當時就覺得相當的有想象力的一種實現。那讓我們看一下這個正則表達式是如何做判斷素數的。

  • 第一步,創建了一個長度為i,並以'*'填充的字符串。

  • 第二步,讓這個后面的正則表達式去匹配這個字符串,如果匹配則不是質數。

過程很簡單。讓我們看一下這個正則表達式。

能被這個正則表達式匹配出則這個數不是素數,這個正則表達式可以分成兩部分看,

  • 第一部分:^.?$^匹配字符串起始位置,$匹配字符串結束位置,.表示匹配單個任意字符,?表示可選。合起來的意思就是匹配只有一個字符或者沒有字符的字符串,也就是0或者1。0或1不是質數,這里特殊匹配這兩個數字。
  • 第二部分:^(..+?)\1+$。這部分是關鍵。先拆開來解釋一下意思,^$就不解釋了。(..+?)表示匹配兩個及以上的任意字符,這里的+?表示它是忽略優先(lazy)的,對結果來說沒有影響,出於性能考慮。注意到這個表達式有一個括號,這個是一個捕獲型括號。\1是反向引用,引用的內容就是前面第一個括號選中的內容。那么后面\1+的意思就是匹配前面括號匹配中的內容一次或多次。

這個表達式基本內容解釋完了,那么為什么能夠匹配非素數呢?

匹配的過程大致是這樣子的,(..+?)首先匹配2個字符,然后\1+匹配2的倍數個字符,如果能夠匹配是不是就說明了這個數是2的倍數啦?當匹配失敗的時候,匹配引擎將(..+?)匹配三個字符,然后\1+匹配3的倍數個字符,如果能夠匹配則是3的倍數。依此類推。。。。。。

如果匹配了則說明這個數必定能夠被某一個數整除,如果匹配完都沒匹配到則說明從2到n-1的數都不能整除n,那就證明這個數是素數!

 

題外話

(..+?)?的作用,我認為這個是為了提高性能的。如果沒有?的話(..+?)會試圖把所有的字符都匹配完,然后發現后面還有表達式,於是從最后一個位置開始回溯。而加了?則是從第二個就開始往后去匹配。

打個比方:我們匹配12。^.?$|^(..+)\1+$會做的事情是先判斷12是不是11的倍數、then 12是不是10的倍數........then 12是不是6的倍數。^.?$|^(..+?)\1+$會做的是先判斷12是不是2的倍數,then 就沒then了。對於素數的效率是一樣的,因為每個位置都需要匹配過來,但是對於非素數從小開始匹配則能夠讓這個表達式早點結束匹配。

如果你覺得我解釋的不清楚沒明白,下面有其他人的解釋:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM