序
克制我們內心的衝動
《正規表示法》(第2版)就要出版了,本來這是個好消息。在這之前,我更想做的是克制自己內心的衝動,靜下心來講講這本書的故事。
《正規表示法》初版剛出版的時候,我一度認為,自己和正規表示法的緣分到此為止了。如果說翻譯《精通正規表示法》之後還有許多遺憾,比如某些講解方式不符合華語程式師的思維,以及過份關注英文,所以關於東亞文字處理的知識無從尋找,經驗無從分享。那麼寫作《正規表示法》,就是彌補這種缺憾的絕好機會。《正規表示法》面世之後,這些缺憾已經悉數補上了。
令我沒有想到的是,《正規表示法》自2012年出版以來,不斷有讀者向我回饋問題。除去最早一兩年密集熱烈的回饋,後續的回饋如涓涓細流綿綿不絕。而我一度想當然地認為勘誤已經完整了,所以一直沒檢查勘誤信箱。直到一年前讀者在微信公眾號後台給我留言,詳細列明勘誤意見之外,毫不留情地指責「對自己的作品不負責,長期不回覆讀者意見」。這封信讓我慚愧不已。在軟體發展中,「發佈了就不管」是很不負責的,在技術書籍的寫作中,「出版了兩年就不回覆讀者意見」,同樣是很不負責的。
所以,我必須克制自己內心「年代久遠,不值得繼續打理」的偷懶衝動。文責自負,完整的說法應該是「文責終身自負」。
本次《正規表示法》(第2版)的出版,對我而言是全新的彌補機會,可以「一次性」回覆迄今為止所有的讀者意見。當然,新增的Objective-C、Golang等章節,儘管已經找熟悉的朋友審讀過,但我可以肯定,它們必定不是完美無瑕的,未來仍然需要坦然面對廣大讀者持續的批評指正。哪怕有些批評指正的語氣不那麼讓人舒服,甚至「看不到幾分善意」,我仍然需要克制自己內心「反唇相譏」的衝動,認清事實,撇開情緒,虛心面對。
同時,我也希望讀者在閱讀這本書時,能克制自己內心的衝動。
我希望大家克制的第一重衝動,是淺嘗輒止—「正規運算式這玩意兒,要用時翻翻就好,沒必要深究」。正規運算式已經誕生很多年了,以今天的標準來看,它的語法和結構相當粗陋,不幸的是,它的內部邏輯又相當複雜。有些朋友會問我一些「怎麼看也看不懂」的正規運算式,坦白地說,我也要反復琢磨才能看懂。所以,儘管這本書提供了若干「速查」資料,但我還是建議讀者能耐下心來,至少通讀一遍。正規運算式有點像游泳,學會了就不會忘,用的時候自然能想起來。否則,你永遠只能在岸邊撲騰,離開了其他人的協助,一步都不敢往深處去。雖然很多時候,與你要的東西就只有一步之遙。
我希望大家克制的第二重衝動,是玩弄正規表示法的快感。前面說過,正規運算式的語法和結構相當粗陋,內部邏輯又相當複雜,所以不少人學會之後,產生了「掌握神奇魔咒」的快感。凡是和字串相關的處理必亮出神奇的正規運算式,能用一個正規表示法的絕不用兩個,能用高級特性的絕不用簡單特性……隨之而來的是其他人debug時層出不窮的抱怨,更不用提更新時膽戰心驚的煩惱。要知道,熟練使用正規運算式,卻不濫用正規運算式,同時考慮合作同事的感受和效率,才能真正贏得大家的尊敬。
武學大師說:武功不是用來傷害,而是用來制止傷害的。哲學大師說:沒有審慎思考,不懂得克制的人生,是不值得過的。這些道理聽起來有悖常理,我花了不少時間才終於弄懂。我相信,正在閱讀這本書的你,也應當懂得這些道理。
特別感謝兩位女士,西喬和劉舫。西喬為這本書設計的封面,絲毫不受歲月的影響。劉舫編輯細緻嚴謹的工作態度,支撐著我完成《正規表示法》的第2版,再寫下這篇序。
余晟
2018年9月3日
前言
提到正規表示法,許多人很有點不屑一顧:這東西,不登大雅之堂,再說也不是總要用到,何必專門花時間學習?
沒錯,正規表示法並不「總要用到」,但到了需要的場合用不上,常常產生「一分錢難倒英雄漢」的尷尬。經常需要處理文字的程式設計師自然會知道正規表示法的價值,其他的程式設計師如果不會正規表示法,即使開發的領域與文字處理沒什麼關係,也難免「躺著中槍」的命運——前幾天我遇到一個問題,將一行長長的位址拆分成多行,負責這部分的程式設計師的日常工作只是製作PDF而已,拆分地址是很「邊緣」的功能,但不會正規表示法就無法準確折行(一般需要在標點符號出現的地方折行,而不能只在空白字元處折行,但是不同語言中的標點符號各有不同),結果一籌莫展;相反,如果了解正規表示法,就可以很容易地處理各種語言中的標點字元。
以我的開發經驗來看,專門花點時間熟練正規表示法,確實是非常有必要的。目前可以見到的關於正規表示法的書籍和資料有不少,但又各有不足。
在網際網路上,流傳著一些程式語言的正則文件和《30分鐘教會你正規表示法》之類的發文。這種資料的好處是簡單直接,查到了,如果有現成的實例,而且適用於自己的語言,則可以直接拿來用;然而,其壞處也是簡單直接,因為缺乏背後原理的說明,如果找不到現成的實例,或找不到能在自己所使用語言中行得通的實例(需知道,同樣的正規表示法並不能直接套用到不同的語言中),則束手無策。
在正式的出版領域,已經有《精通正規表示法》、《正規表示法一定要會》之類的書籍出版,尤其是前者,堪稱關於正規表示法的經典著作,如果想認真學習正規表示法,這種書籍是必須閱讀的。但這種書籍也有一個弱點,即都是由英文版本翻譯而來的,更多地偏重英文文字的處理,身為中文世界的開發人員,我們經常需要處理中文文字——對於處理英文之外的字元,正規表示法已經提供了足夠豐富的功能,但如何用對、用好這些功能,資料卻很匱乏。
我經常需要給人說明正規表示法的相關知識,時常惋惜的是,開發人員為這些問題所困擾;正因為如此,本書的寫作動機便是著力彌補現有資料的缺陷。
相對於正則文件和速成教學發文,本書深入說明了比對背後的原理,常常會舉一反三,告訴讀者,這裡為何這樣寫,如果改成其他形式,會造成什麼結構;並且,集中說明和比較了多種語言中正規表示法用法的異同,方便讀者把現成的正規表示法「移植」到自己的工作環境中。
相對於《精通正規表示法》等正式的書籍,本書辟出專門的內容說明語言和編碼,告訴讀者如何設定編碼,如何正確處理中文等字元。另外,本書還涵蓋了.NET、Java、JavaScript、PHP、Python、Ruby、Objective-C、Golang等常用語言,對每種語言列出專門章節,不但詳細介紹了語言中正規表示法的用法,更點明了版本之間的細微差異,不但可以作為專門學習的教材,還可以成為有用的參考手冊。
本書結構
本書可以分為三大部分。
第一部分主要說明正規表示法的基礎知識,覆蓋常見正規表示法中的各種功能和結構。看完前面3章,就可以基本弄明白現在流行的各種正規表示法;尤其是如果你之前有一些經驗,會覺得閱讀起來並不困難。但是我也希望讀者不要忽略其他的內容,斷言和比對模式現在已經是正規表示法的「標準配備」了,而且確實可以派上大用場,所以第4章和第5章的內容,即使不是很熟悉,閱讀起來可能有一些麻煩,也不應該忽略。最後的第6
章,則厘清了正規表示法在使用中的許多疑惑,了解它們,你就可以相對自由地在正規表示法的世界裡行走了。
第二部分主要說明關於正規表示法的更深入的知識,這一部分用3章的內容,詳細探討了編碼問題、比對原理、求解想法。這部分內容更抽象,需要多花一點時間來閱讀和了解,但是它們確實可以幫你在正規表示法的世界裡登堂入室,脫離「術」的層面,熟練萬變不離其宗的「道」。
第三部分的作用是普遍性的推展,將之前介紹的各種知識落實到常用語言.NET、Java、JavaScript、PHP、Python、Ruby、Objective-C、Golang中來。每一章的開頭有正則功能列表,其中的功能都對應著前面部分的說明,這些功能的實際應用實例,以及不同版本之間的差異,則在章節中詳細說明,每一章的最後還列出了常見工作的範例程式,方便日後查詢。在最後,第18章簡介了正規表示法在Linux下常用工具vi、grep、awk、sed
中的使用,並透過一個實際的實例將這幾種工具串起來,比較說明了它們適合解決的問題。
在本書的最後提供了用作參考的3個附錄。
附錄A是正規表示法的常用功能在不同語言中的比對,希望能給需要在多種語言中使用正規表示法或移植正規表示法的讀者提供一份有用的參考;附錄B列出了許多常見的正規表示法,例如比對郵遞區號、身份證字號、手機號、QQ號、電子郵寄地址等,希望能成為常見問題的「速查手冊」;附錄C列出了常用正規表示法的工具和資源,方便大家偵錯自己的正規表示法,以及繼續深入學習。
本書讀者
本書適合以下幾種讀者。
經常需要進行文字處理(例如記錄檔分析或網路運行維護)的技術人員。這些讀者或許已經熟悉了正規表示法的基本用法,但以日益複雜化和海量化為目的的資料,閱讀本書可以幫助你更準確、更高效率地處理文字,提升自己工作的價值。
熟悉常用開發語言的程式設計師。雖然這些讀者不需要專職進行文字處理,但原始程式碼和許多資料其實也是文字,如果不會正規表示法,在偶然遇到處理原始程式碼或文字資料的工作時,常常會產生躺著中槍的無力感。本書第三部分可以幫你迅速找到有關的實例,並完成在自己的程式語言中。當然前兩部分也非常有必要,因為它們可以幫你夯實基礎。
對正規表示法已經有一定了解的讀者。這些讀者雖然能用正規表示法解決常見的工作,但未必了解正規表示法的編碼問題、比對原理、求解想法,仔細閱讀本書的第二部分,可以深化增強對正規表示法的了解;而第三部分詳細比較了使用正規表示法時各種語言,以及同一種語言中各種版本的差異。所有這一切,應該可以讓你對正規表示法的熟練更上一層樓。
致謝
一本書的完成,必然離不開許多人的幫忙。
首先要感謝的是李笑來老師、周筠老師、徐定翔和盧鶇翔兩位編輯。在我翻譯完《精通》之後,李笑來老師三番五次地鼓勵我寫一本關於正規表示法的書,並且打消了我的很多顧慮;周筠老師、徐定翔和盧鶇翔兩位編輯在我寫作的最初階段做了大量細緻耐心的工作。可以說,沒有他們,我就不會有寫作這本書的念頭,也不會有堅持完成的動力。
然後要感謝的是電子工業出版社的楊福平副總編和張月萍編輯,沒有他們的關照和辛勞工作,這本書的出版定然會遇到更多的困難。
感謝我的朋友霍炬和韓磊,雖然我之前閱讀過《精通正規表示法》,但與翻譯和寫作結緣,他們給了我莫大的幫助,有了這個契機,才有了現在這本書。
感謝我曾工作過的盛大創新院以及創新院的各位同事(李駿、郝培強、莊表偉、丁宇、許式偉、莫華楓、李道兵、趙劼、樊一鵬、張一甯等),創新院給了大家寬鬆自由的工作環境,與各位同事的討論加深了我對正規表示法的了解,也為我提供了許多實例。
感謝張東亮、陸亦斌、孫勇、葉勁峰等各位朋友,願意撥冗閱讀本書的草稿,並提出了大量專業的意見。
感謝何源、陳鋼、賀鈞、陳馳等讀者,試讀本書之後提出了大量的寶貴意見,在最後關頭打消了我心中的許多忐忑。
在更早之前,我的父母從小就鼓勵我研究和了解各種科學原理(「玩也要動腦筋」),我之所以有興趣深入正規表示法背後的世界,而不滿足於「夠用/湊合」,歸源都是受益於這種思維行為習慣。此外,在中小學階段,我的語文老師羅碧玉、郭志鴻、易璽銘培養了我對於文字的興趣,在大學階段,東北師範大學文學院的王確老師給了我這個理科生非常多的幫助和指引。對各位師長,在此一併表示感謝,能遇到你們是我的幸運。
最後還需要感謝許多為這本書做出過貢獻的人,你們的名字我可能暫時無法記起,或無法一一羅列,但我會在心中存留對你們的謝意。