天天看點

《正規表達式經典執行個體(第2版)》——2.18 向正規表達式中添加注釋

本節書摘來自異步社群《正規表達式經典執行個體(第2版)》一書中的第2章,第2.18節,作者: 【美】jan goyvaerts , steven levithan著,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視

問題描述

‹d{4}-d{2}-d{2}›可以比對一個yyyy-mm-dd形式的日期,但是不會對數字做任何檢查。當你知道資料中不會包含非法日期時,這樣一個簡單的正規表達式就夠用了。試着在該正規表達式中添加注釋來說明該正規表達式的每個部分的含義。

解決方案

讨論

寬松排列模式

正規表達式很容易變得複雜無比并且難以了解。源代碼中應該添加注釋,是以隻要正規表達式稍微複雜一點,你也應該在其中添加注釋。

本書中除了javascript之外的所有正規表達式流派,都提供了某種形式的正規表達式文法來幫助你很容易清晰地注釋正規表達式。你可以通過開啟寬松排列(free-spacing)模式來應用這種文法。在不同的程式設計語言中它可能會有不同的名稱。

在.net中,需要設定regexoptions.ignorepatternwhitespace選項。而在java中,則要傳遞pattern.comments标志。python用的是re.verbose。php、perl和ruby則使用/x标志。

盡管标準javascript并不支援寬松排列,但xregexp庫添加了這個選項。隻需在xregexp()構造器第二個參數标志中添加'x'即可。

打開寬松排列模式會産生兩個效果。首先,它會把位于字元組之外的井号(#)轉變成一個元字元。井号會作為一個注釋的開始,該注釋的結尾是一行的結束或者該正規表達式的結束(取二者中先到的那個)。井号以及其後的所有内容都會被正規表達式引擎直接忽略。如果要比對一個字面上的井号字元,必須把它放到一個字元組‹[#]›中,或者把它轉義為‹#›。

寬松排列模式的另外一個效果是:位于字元組之外的所有空白字元,包括空格、制表符和換行符,都會被忽略。要想比對一個字面上的空格,就需要把它放到字元組‹[●]›中,或者把它轉義為‹●›。如果你更關心可讀性的話,那麼也可以選擇使用十六進制數的轉義形式‹x20›,或者是unicode轉義形式‹u0020›或‹x{0020}›來代替。如果要比對一個制表符,則應該使用‹t›。至于換行符,則可以使用‹rn›(windows)或者‹n›(unix、linux、os x)。

寬松排列模式并不會改變位于字元組之内的任何内容。一個字元組可以看作是單個記号。位于字元組之内的任意空白字元或者井号都是被添加到字元組中的字面字元。打斷字元組來對其中的某個部分進行注釋是不允許的。

java中的寬松排列字元組

如果完全不存在與其他不相容的流派,正規表達式的複雜性也不會讓人談之生變。在這裡,不相容的那個流派就是java。

在java中,字元組并不作為單個記号來進行分析。如果你打開了寬松排列模式,那麼java就會忽略字元組中的空格,而且在字元組中的井号也意味着注釋的開始。這就意味着,你不能使用‹[●]›和‹[#]›來字面比對這些字元。使用‹u0020›和‹#›作為替代。

變體

不管是出于什麼原因,如果你不能或者是不想使用寬松排列文法,那麼還可以通過‹(?#comment)›的方式添加注釋。在‹(?#›和‹)›之間的所有字元都會被忽略。

不幸的是,javascript,也就是本書中講到的流派中唯一不支援寬松排列的流派,同樣也不支援這種注釋文法。xregexp為javascript添加了寬松排列支援,同樣也添加了這種注釋文法支援。而java支援寬松排列模式下添加注釋,卻不支援‹(?#comment)›這種文法。

如果不能在正規表達式之外啟用寬松排列模式,那麼你可以把模式修飾符‹(?x)›放到正規表達式的最開始處。確定‹(?x)›之前不存在任何空格。因為隻有在這個模式修飾符之後才會開始寬松排列模式,是以在它之前的任意空格都是不能忽略的。