Python把C語言打得滿地找牙

來源:互聯網
上載者:User

好吧,我承認我又標題黨了,不該把Python拉出來和C比,我絕無輕視C語言的意思。我想說的只是,在解決某些問題是,比起用C,用Python真是太舒服了。

《Beautiful Code》開篇第一章是由大神Brian Kernighan講解另一位半神半程式員Rob Pike設計的C語言“正則”運算式引擎(“正則“二字打引號的原因下面會說明)。不能不說短短几十行代碼是讓人歎為觀止的大師傑作。 具體好在哪裡我也不重複了,如果我都能對這段代碼頭頭是道,那也不勞Kernighan親自出場讚不絕口了。總之,他說:I was amazed by how compact and elegant this code was... 我覺得,既然Kernighan都如此讚賞,論“compat and elegant”,這一定是C語言的最高境界了。估計這也是程式設計的最高境界了吧?一段時間裡,我深信不疑,直到有一天,我看見了這個Regular expression engine in 14 lines of Python。再次驚歎。

首先,整理一下這段代碼,實際上,原帖中的代碼還不夠精簡,因為它用3行實現了一個Python標準庫中已有的函數。取消這三行,改為用import引入庫函數,得到的代碼如下:

from itertools import chain as iconcat

def nil(s): yield s

def seq(l, r):
    return lambda s: (sr for sl in l(s) for sr in r(sl))

def alt(l, r):
    return lambda s: iconcat(l(s), r(s))

def star(e):
    return lambda s: iconcat(nil(s), seq(e, star(e))(s))

def plus(e): return seq(e, star(e))

def char(c):
    def match(s):
        if s and s[0] == c: yield s[1:]
    return match

就代碼量來看,和《Beautiful Code》中的C“正則”引擎相差不大,但此Python實現的正則引擎在功能和簡單性上都有無可比擬的優勢,在分析這個正則引擎如何使用,順帶說明其工作原理後,再來看它的好處。

使用這個正則引擎時首先用char, nil, sq, alt, star, plus這幾個函數構造出一個Regex,用BNF記號表示,格式是這樣的:

exp -> char(c) |
       nil |
       seq(exp, exp) |             
       alt(exp, exp) |
       star(exp) |
       plus(exp)

其語義為:

exp->char(c) 表示匹配以字母c開頭的字串;

exp->nil 表示匹配一個Null 字元串;

exp->seq(exp1, exp2)表示如果exp1匹配s1,exp2匹配s2,則exp匹配由s1和s2串連成的字串;

exp->alt(exp1, exp2)表示字串s必須匹配exp1或exp2中的一個;

exp->star(exp1)匹配Null 字元串,或由一個或多個匹配exp1的子字串串連成的字串;

exp->plus(exp1)匹配由一個或多個匹配exp1的子字串串連成的字串。

總之不論格式還是語義它都和教科書上的Regex完全一致。例如,Regexe=c(a|d)*r用這個正則引擎表到出來就是:

e = seq(char('c'),

                seq(plus(alt(char('a'), char('d'))),

                        char('r'))

現在是使用的問題了。構造出來的Regex的Python類型是函數,此函數接受一個參數,即被匹配的字串。調用此函數得到的結果是一個集合,其中每一個元素為一個字串,對應一個Regex和目標字串的匹配,而這個字串的內容就是目標字串中剩下的無法匹配的部分。也就是說,如果Regex可以和目標字串匹配,則返回的集合不為空白,反之則得到一個空集合,因此,我們可以用:

if e(str):

來判斷Regexe是否和字串str匹配。

要理解這個正則引擎的工作原理,只要抓住前述的一點“調用此函數得到的結果是一個集合,其中每一個元素為一個字串,對應一個Regex和目標字串的匹配,而這個字串的內容就是目標字串中剩下的無法匹配的部分“。實際上nil, char, seq, alt, plus中的每一個都符合此定義。這也是此Python正則引擎設計的好處之一:簡單明了,易於理解,易於實現,易於確保正確。要寫出《Beautiful Code》中的正則引擎是相當難的。我承認,以我的水平,即使Rob Pike把他的設計告訴我讓我寫代碼,我也無法正確的寫出。迴圈、指標還有邊界條件,實在太容易出錯了,這樣的代碼,非出自大師之手不可。而Python版的正則引擎就不一樣,簡單清晰的語義,很好的模組性,即使讓我來寫也可一次寫對。

雖然代碼量相當,但是此Python 在功能上大大強過C版。首先,C版並不是一個真正的正則引擎。它無法表達“匹配exp1或匹配exp2”,這大大的限制它的實用性,而Python版是教科書式的標準正則引擎。其次,C版不能表達(abc)*這樣的運算式,即其Kleene closure中的內容只能是一個字母,而Python版Kleene closure中可以是任何錶達式。這就是為什麼開頭“正則”二字要加引號。

此Python版代碼的可組合性也比C版好。如果要在原有的基礎上添加功能,Python版的使用者只需要添加新的函數,而C版則要修改已有函數,難易程度不可同日耳語。比如注意到Python版沒有“匹配任一字元”的功能,我們只需添加兩行代碼即可實現此功能:

def any(s):
    yield s[1:]

不僅實現簡單,而且因為不改動已有代碼,測試也容易。

為什麼在實現一個簡單的正則引擎這個任務上,Python比C版順手許多呢。看看Python版中用到的C所不具備的語言特性:generator function, generator expression, 高階函數,string slicing。string slicing不僅僅是一個簡單的產生子字串的運算式,支撐其易用性是Python的自動記憶體管理。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.