學習正則表達式最好的方式是讀《精通正則表達式》這本書:
《精通正則表達式》
建議認真學完前6章,后面與具體編程語言相關的可以跳過?;ㄒ恍r間系統(tǒng)地學習一下正則表達式是非常有好處的。就像張無忌學會九陽神功后學其他武功都特別快,學會正則表達式后再學習UNIX/Linux的下的工具也都特別快!
除了推薦書籍,我也分享一下我自己讀寫正則表達式的心得。
如何讀正則表達式?
《精通正則表達式》這本書讓我認識到,正則表達式只是一種描述字符串長什么樣的聲明式語言,是字符串的元信息。就像SQL是用來描述數據長什么樣的聲明式語言,只是SQL使用更直觀的英文單詞作為關鍵詞,而正則表達式使用的是更加精煉但也更加晦澀的符號字符。
所以,學習正則表達式與學習其他語言的過程是一樣的,需要學會這門語言的詞法、語法、語義。如果對這些詞法、語法、語義不熟悉,看正則表達式就像天書一樣。
詞法
如前文所述,正則表達式的單詞由標點符號字符組成。和漢語、英語等自然語言一樣,這些單詞也有詞性,包括字符(character)、字符類(character class)、分組(grouping)、量詞(quantifier)、錨點(Anchor)等。
想要一股腦記住所有符號及其含義,就像從頭到尾背英語詞典一樣,是很低效且痛苦的。好在正則表達式的單詞也符合2-8法則,就像英語里的常用詞一樣并不多,諸如零寬斷言等用法其實不太常用,用到的時候臨時查文檔復習一下用法就行。
以下幾個字符是最最常用的元字符:
單詞 | 詞性 | 語義 |
^ | 錨點 | 以……開頭 |
$ | 錨點 | 以……結尾 |
. | 字符集 | 任意字符 |
* | 量詞 | 任意多個 |
+ | 量詞 | 1個或多個 |
? | 量詞 | 0個或1個 |
需要注意的是,除了惰性匹配的量詞,其他量詞默認都是貪心匹配,即盡可能多地匹配、直到無法匹配為止。
語法
正則表達式的語法并不多,除了要開閉括號要能一一對應,也就是量詞只能放在字符、字符集、分組的后面。
示例
舉個例子:
/^ab+c*$/
該模式讀作:“有一些字符串,它們以1個a開頭,緊接著1個或多個b,最后以任意多個c結尾?!狈线@個規(guī)則的字符串很多,有“ab”、“abc”、“abbccc”等等。
如何寫正則表達式?
有了前文讀正則表達式的基礎,基本上也能照葫蘆畫瓢寫正則表達式了,但新手在寫正則表達式的時候往往容易忽略“上下文”,會寫出非常具體、非常長的模式。因為正則表達式的主要用途就是用于文本匹配,所謂的“上下文”就是正則表達式預計在那些文本中匹配。上下文不同,解法也可以不同。
舉個例子,一個爬蟲爬取到以下HTML頁面信息:
- Bob
- William
- Vina
假設希望在這些內容中匹配出包含「朋友姓名」的行,比較簡單的方式有:
/class=”name”/
還能更簡潔一些:
/name/
或者更具體一些:
/[^]+/
這三種方式哪種最好呢?這個得視情況而定。我的建議是:
如果數據來源比較可控,例如內部系統(tǒng)生成的數據,則盡量寫簡單有效的模式;
如果數據來源不可控,例如網絡爬蟲從外部系統(tǒng)抓取的數據,內容隨時都有可能發(fā)生變化,那適度地優(yōu)化一下正則表達式,讓模式具備一些彈性去適應可預見的一些變化。
如果讓我來寫這個例子的正則表達式,我會傾向于這樣寫:
/class=”[^”]*bnameb[^”]*”/
這樣既具備一定的彈性,例如未來添加了其他class,或li換成其他tag,都能自動適應;又不會過于復雜。
綜上所述,正則表達式并沒有唯一的標準答案,需要根據待匹配文本的上下文選擇復雜度最合適的方案。因此,寫正則表達式時不用著急,不必要求自己一次就寫對。應該像寫SQL一樣在數據集上多select幾次,對數據集有了較全面的認知后,不斷修正數據過濾條件,就能優(yōu)化出比較精煉的SQL;同樣的,寫正則表達式也是在目標字符串上反復篩選,最后就能優(yōu)化出比較精煉的模式。