正則指引(第2版)( 簡體 字) | |
作者:余晟 | 類別:1. -> 程式設計 -> 綜合 |
出版社:電子工業出版社 | 3dWoo書號: 50079 詢問書籍請說出此書號! 有庫存 NT售價: 445 元 |
出版日:10/1/2018 | |
頁數:388 | |
光碟數:0 | |
站長推薦: | |
印刷:黑白印刷 | 語系: ( 簡體 字 ) |
ISBN:9787121351303 | 加入購物車 │加到我的最愛 (請先登入會員) |
(簡體書上所述之下載連結耗時費功, 恕不適用在台灣, 若讀者需要請自行嘗試, 恕不保證, 繁體書的下載亦請直接連絡出版社) | |
第一部分
第1章 字符組 .................2 1.1 普通字符組 ............. 2 1.2 關于Python的基礎知識........................... 4 1.3 普通字符組(續) . 6 1.4 元字符與轉義 ......... 8 1.5 排除型字符組 ....... 10 1.6 字符組簡記法 ....... 12 1.7 字符組運算 ........... 14 1.8 POSIX字符組 ...... 15 第2章 量詞 ...................17 2.1 一般形式 ............... 17 2.2 常用量詞 ............... 19 2.3 數據提取 ............... 21 2.4 點號....................... 23 2.5 濫用點號的問題 ... 23 2.6 忽略優先量詞 ....... 26 2.7 轉義....................... 31 第3章 括號 ...................33 3.1 分組....................... 33 3.2 多選結構 ............... 39 3.3 引用分組 ............... 44 3.3.1 反向引用... 48 3.3.2 各種引用的記法 .......................... 50 3.3.3 命名分組... 53 3.4 非捕獲分組 ........... 55 3.5 補充....................... 56 3.5.1 轉義 .......... 56 3.5.2 URL Rewrite ................................ 56 3.5.3 一個例子... 58 第4章 斷言 ...................60 4.1 單詞邊界 ............... 60 4.2 行起始/結束位置 .. 62 4.3 環視....................... 69 4.4 補充....................... 75 4.4.1 環視的價值 .................................. 75 4.4.2 環視與分組編號 .......................... 76 4.4.3 環視的支持程度 .......................... 77 4.4.4 環視的組合 .................................. 79 4.4.5 斷言和反向引用之間的關系 ...... 81 4.4.6 逆序環視的詭異之處 .................. 81 第5章 匹配模式 ............83 5.1 不區分大小寫模式與模式的指定方式 .. 83 5.2 單行模式 ............... 86 5.3 多行模式 ............... 87 5.4 注釋模式 ............... 89 5.5 補充....................... 91 5.5.1 更多的模式 .................................. 91 5.5.2 修飾符的作用范圍 ...................... 91 5.5.3 失效修飾符 .................................. 92 5.5.4 模式與反向引用 .......................... 93 5.5.5 沖突策略... 93 5.5.6 哪種方式更好 .............................. 94 第6章 其他 ...................95 6.1 轉義....................... 95 6.1.1 字符串轉義與正則轉義 .............. 95 6.1.2 元字符的轉義 .............................. 99 6.1.3 徹底消除元字符的特殊含義 .... 101 6.1.4 字符組中的轉義 ........................ 103 6.2 正則表達式的處理形式 ........................ 103 6.2.1 函數式處理 ................................ 104 6.2.2 面向對象式處理 ........................ 104 6.2.3 比較 ........ 105 6.2.4 線程安全性 ................................ 106 6.3 表達式中的優先級 ................................ 108 6.4 回車和換行 ......... 109 第二部分 第7章 Unicode ...........112 7.1 基礎知識 ............. 112 7.2 關于編碼 ............. 115 7.3 盡量使用Unicode編碼 ........................ 116 7.4 Unicode與字符組簡記法 ..................... 120 7.5 規范化問題 ......... 122 7.6 單詞邊界 ............. 123 7.7 碼值轉義序列 ..... 125 7.8 Unicode屬性 ...... 127 7.8.1 Unicode Property ....................... 128 7.8.2 Unicode Block ........................... 128 7.8.3 Unicode Script ........................... 129 7.9 Unicode屬性列表 ................................. 130 7.9.1 Unicode Property ....................... 130 7.9.2 Unicode Block ........................... 131 7.9.3 Unicode Script ........................... 135 7.10 POSIX字符組 .. 135 7.11 Emoji ................. 136 第8章 匹配原理 ..........138 8.1 有窮自動機 ......... 138 8.2 正則表達式的匹配過程 ........................ 139 8.3 回溯..................... 142 8.4 NFA和DFA ....... 144 第9章 常見問題的解決思路 ...........................146 9.1 關于元素的三種邏輯 ............................ 146 9.1.1 必須出現. 147 9.1.2 可能出現. 147 9.1.3 不能出現. 148 9.2 正則表達式的常見操作 ........................ 150 9.2.1 提取 ........ 150 9.2.2 驗證 ........ 156 9.2.3 替換 ........ 160 9.2.4 切分 ........ 165 9.3 正則表達式的優化建議 ........................ 167 9.3.1 使用緩存. 167 9.3.2 盡量準確地表達意圖 ................ 168 9.3.3 避免重復匹配 ............................ 168 9.3.4 獨立出文本和錨點 .................... 169 9.4 別過分依賴正則表達式 ........................ 170 9.4.1 徹底放棄字符串操作 ................ 170 9.4.2 思維定式. 171 9.4.3 正則表達式可以匹配各種文本 172 9.4.4 濫用正則表達式 ........................ 173 第三部分 第10章 .NET ..............176 10.1 預備知識 ........... 176 10.2 正則功能詳解 ... 177 10.2.1 列表 .... 177 10.2.2 字符組 178 10.2.3 Unicode屬性 ......................... 178 10.2.4 字符組簡記法........................ 179 10.2.5 單詞邊界 ............................... 179 10.2.6 行起始/結束位置 .................. 180 10.2.7 環視 .... 181 10.2.8 匹配模式 ............................... 181 10.2.9 捕獲分組的引用 .................... 182 10.3 正則API簡介 .. 183 10.3.1 Regex .. 183 10.3.2 Match .. 187 10.4 常用操作示例 ... 188 10.4.1 驗證 .... 188 10.4.2 提取 .... 189 10.4.3 替換 .... 189 10.4.4 切分 .... 190 第11章 Java ..............191 11.1 預備知識 ........... 191 11.2 正則功能詳解 ... 192 11.2.1 列表 .... 192 11.2.2 字符組. 192 11.2.3 Unicode屬性 ......................... 194 11.2.4 字符組簡記法 ........................ 194 11.2.5 單詞邊界 ................................ 194 11.2.6 行起始/結束位置 ................... 195 11.2.7 環視 .... 196 11.2.8 匹配模式 ................................ 196 11.2.9 純文本模式 ............................ 197 11.2.10 捕獲分組的引用 .................. 197 11.3 正則API簡介 .. 197 11.3.1 Pattern . 198 11.3.2 Matcher .................................. 200 11.3.3 String ... 203 11.4 常用操作示例 ... 204 11.4.1 驗證 .... 204 11.4.2 提取 .... 204 11.4.3 替換 .... 205 11.4.4 切分 .... 206 11.5 Java 8和Java 9的新改進 ................... 206 11.5.1 Java 8的新改進 ..................... 206 11.5.2 Java 9的新改進 ..................... 207 第12章 JavaScript .....208 12.1 預備知識 ........... 208 12.2 正則功能詳解 ... 209 12.2.1 列表 .... 209 12.2.2 字符組 210 12.2.3 字符組簡記法........................ 211 12.2.4 單詞邊界 ............................... 211 12.2.5 行起始/結束位置 .................. 212 12.2.6 環視 .... 212 12.2.7 匹配模式 ............................... 213 12.2.8 捕獲分組的引用 .................... 214 12.3 正則API簡介 .. 215 12.3.1 RegExp 215 12.3.2 String ... 218 12.4 常用操作示例 ... 221 12.4.1 驗證 .... 221 12.4.2 提取 .... 222 12.4.3 替換 .... 223 12.4.4 切分 .... 223 12.5 關于ActionScript ................................ 223 12.5.1 RegExp 223 12.5.2 匹配規則 ............................... 224 12.5.3 匹配模式 ............................... 224 12.5.4 正則API ................................ 224 第13章 PHP ...............225 13.1 預備知識 ........... 225 13.2 正則功能詳解 ... 227 13.2.1 列表 .... 227 13.2.2 字符組 228 13.2.3 Unicode屬性 ......................... 229 13.2.4 字符組簡記法........................ 229 13.2.5 單詞邊界 ............................... 230 13.2.6 行起始/結束位置 .................. 230 13.2.7 環視 .... 231 13.2.8 匹配模式 ............................... 231 13.2.9 純文本模式 ........................... 232 13.2.10 捕獲分組的引用 .................. 232 13.3 正則API簡介 .. 233 13.3.1 PREG 常量說明 ................... 233 13.3.2 preg_quote ............................. 235 13.3.3 preg_ grep .............................. 235 13.3.4 preg_match ............................. 236 13.3.5 preg_match_all ....................... 237 13.3.6 preg_last_error ....................... 239 13.3.7 preg_replace ........................... 239 13.3.8 preg_replace_callback ............ 240 13.3.9 preg_filter ............................... 240 13.3.10 preg_split ............................. 241 13.3.11 preg_replace_callback_array 242 13.4 常見的正則操作舉例 .......................... 243 13.4.1 驗證 .... 243 13.4.2 提取 .... 243 13.4.3 替換 .... 244 13.4.4 切分 .... 244 第14章 Python ...........245 14.1 預備知識 ........... 245 14.2 正則功能詳解 ... 246 14.2.1 列表 .... 246 14.2.2 字符組 247 14.2.3 Unicode屬性 ......................... 248 14.2.4 字符組簡記法........................ 249 14.2.5 單詞邊界 ............................... 250 14.2.6 行起始/結束位置 .................. 251 14.2.7 環視 .... 252 14.2.8 匹配模式 ............................... 252 14.2.9 捕獲分組的引用 .................... 253 14.2.10 條件匹配 ............................. 253 14.3 正則API簡介 .. 254 14.3.1 RegexObject ........................... 254 14.3.2 re.compile(regex[, flags]) ....... 255 14.3.3 re.search(pattern, string[, flags]) ............................... 256 14.3.4 MatchObject ........................... 256 14.3.5 re.match(pattern, string[, flags]) ................................ 257 14.3.6 re.findall(pattern, string[, flags]) ............................... 258 14.3.7 re.finditer(pattern, string[, flags]) .............................. 258 14.3.8 re.split(pattern, string[, maxsplit=0, flags=0]) .......... 259 14.3.9 re.sub(pattern, repl, string[, count, flags]) ................. 259 14.4 常用操作示例 ... 260 14.4.1 驗證 .... 260 14.4.2 提取 .... 261 14.4.3 替換 .... 262 14.4.4 切分 .... 262 第15章 Ruby ..............263 15.1 預備知識 ........... 263 15.2 正則功能詳解 ... 264 15.2.1 列表 .... 264 15.2.2 字符組 264 15.2.3 Unicode屬性 ......................... 265 15.2.4 字符組簡記法........................ 266 15.2.5 單詞邊界 ............................... 266 15.2.6 行起始/結束位置 .................. 267 15.2.7 環視 .... 268 15.2.8 匹配模式 ............................... 268 15.2.9 捕獲分組的引用 .................... 269 15.3 正則API簡介 .. 269 15.3.1 Regexp 269 15.3.2 Regexp.match(text) ................ 271 15.3.3 Regexp.quote(text)和Regexp.escape(text) ............... 272 15.3.4 String.index(Regexp) ............. 273 15.3.5 String.scan(Regexp) ............... 273 15.3.6 String.slice(Regexp) ............... 274 15.3.7 String.split(Regexp) ............... 274 15.3.8 String.sub(Regexp, Str) .......... 275 15.3.9 String.gsub(Regexp, String) ... 276 15.4 常用操作示例 ... 276 15.4.1 驗證 .... 276 15.4.2 提取 .... 277 15.4.3 替換 .... 277 15.4.4 切分 .... 277 15.5 Ruby 1.9的新變化 .............................. 278 第16章 Objective-C ..280 16.1 預備知識 ........... 280 16.2 正則功能詳解 ... 282 16.2.1 列表 .... 282 16.2.2 字符組 283 16.2.3 Unicode屬性 ......................... 284 16.2.4 字符組簡記法........................ 284 16.2.5 單詞邊界 ............................... 285 16.2.6 行起始/結束位置 .................. 286 16.2.7 環視 .... 287 16.2.8 匹配模式 ............................... 287 16.2.9 純文本模式 ........................... 288 16.2.10 捕獲分組的引用 .................. 289 16.2.11 命名分組 .............................. 290 16.3 正則API簡介 .. 291 16.3.1 predicateWithFormat .............. 291 16.3.2 rangeOfString ......................... 292 16.3.3 regularExpressionWithPattern 292 16.3.4 initWithPattern ....................... 292 16.3.5 pattern . 293 16.3.6 numberOfCaptureGroups ....... 293 16.3.7 numberOfMatchesInString ..... 293 16.3.8 stringByReplacingMatchesInString .......................... 294 16.3.9 replacingMatchesInString ...... 294 16.3.10 escapedPatternForString ...... 294 16.3.11 escapedTemplateForString ... 295 16.4 常用操作示例 ... 295 16.4.1 驗證 .... 295 16.4.2 提取 .... 295 16.4.3 替換 .... 297 16.4.4 切分 .... 298 第17章 Golang...........299 17.1 預備知識 ........... 299 17.2 正則功能詳解 ... 301 17.2.1 列表 .... 301 17.2.2 字符組 301 17.2.3 Unicode屬性 ......................... 302 17.2.4 字符組簡記法........................ 303 17.2.5 單詞邊界 ............................... 303 17.2.6 行起始/結束位置 .................. 303 17.2.7 環視 .... 304 17.2.8 匹配模式 ............................... 304 17.2.9 純文本模式 ........................... 305 17.2.10 捕獲分組的引用 .................. 305 17.2.11 命名分組 .............................. 306 17.3 正則API簡介 .. 307 17.3.1 Compile和MustCompile ...... 307 17.3.2 MatchString ........................... 308 17.3.3 FindString .............................. 308 17.3.4 FindAllString ......................... 309 17.3.5 FindStringIndex ..................... 309 17.3.6 FindAllStringIndex ................ 309 17.3.7 FindStringSubmatch .............. 309 17.3.8 FindAllStringSubmatch ......... 310 17.3.9 SubexpNames ........................ 310 17.3.10 Split ... 311 17.3.11 ReplaceAllString .................. 311 17.3.12 ReplaceAllLiteralString ....... 312 17.4 常用操作示例 ... 312 17.4.1 驗證 .... 312 17.4.2 提取 .... 312 17.4.3 替換 .... 313 17.4.4 切分 .... 313 第18章 Linux/UNIX ....314 18.1 POSIX ............... 314 18.1.1 POSIX規范 ........................... 314 18.1.2 POSIX字符組 ....................... 316 18.2 vi ....................... 317 18.2.1 字符組及簡記法 .................... 317 18.2.2 量詞 .... 318 18.2.3 多選結構和捕獲分組 ............ 319 18.2.4 環視 .... 319 18.2.5 錨點和單詞邊界 .................... 319 18.2.6 替換操作的特殊字符 ............ 320 18.2.7 replacement中的特殊變量 ... 322 18.2.8 補充 .... 322 18.3 grep ................... 323 18.3.1 基本用法 ............................... 323 18.3.2 字符組 324 18.3.3 錨點和單詞邊界 .................... 324 18.3.4 量詞 .... 324 18.3.5 多選結構和捕獲分組 ............ 325 18.3.6 options . 325 18.3.7 egrep和fgrep ........................ 326 18.3.8 補充 .... 327 18.4 awk .................... 327 18.4.1 基本用法 ............................... 327 18.4.2 字符組及簡記法 .................... 328 18.4.3 錨點和單詞邊界 .................... 329 18.4.4 量詞 .... 329 18.4.5 多選結構 ............................... 330 18.4.6 補充 .... 330 18.5 sed ..................... 330 18.5.1 基本用法 ............................... 330 18.5.2 字符組及簡記法 .................... 331 18.5.3 錨點和單詞邊界 .................... 331 18.5.4 量詞 .... 332 18.5.5 多選結構和捕獲分組 ............ 332 18.5.6 options . 333 18.5.7 補充 .... 333 18.6 總結................... 334 附錄A 常用語言中正則特性一覽 ....................337 附錄B 常用的正則表達式 ...............................340 附錄C 常用的正則表達式工具及資源 .............356 正則表達式術語中英文對照表 ...........................363 本書綜合作者自己遇到的實際問題,以及其他開發人員咨詢的問題,總結出一套巧妙運用正則表達式的辦法,并通過具體的例子指導讀者拆解、分析問題。全書分為三部分:第一部分主要講解正則表達式的基礎知識,涵蓋了正則表達式中常見的各種功能和結構;第二部分主要講解關于正則表達式的更深入的知識,詳細探討了編碼問題、匹配原理、解題思路;第三部分將之前介紹的各種知識落實到常用語言.NET、Java、JavaScript、PHP、Python、Ruby、Objective-C、Golang中,在詳細介紹了在這些語言中正則表達式的具體用法之外,還辨析了版本之間的細微差異。本書既可以作為專門的學習用書,也可以作為備查的參考手冊。
引子:關于正則表達式……
正則表達式這個名字看起來總有點古怪,概念似乎也不簡單,甚至需要用一整本書來講解。可是,它到底是什么呢? 同為技術人員,我相信你總會與字符串打交道,相應的,各種語言也都提供了與字符串有關的函數。我們先看下面幾個問題,用字符串函數是如何解決的(下面的代碼使用Python語言,它很直觀,正文里有基礎的介紹。現在,你只需要知道def是定義函數的關鍵詞即可)。 引入正則表達式 1. 判斷字符ch是否是數字字符 def isDigit(ch) : return ch == "0" or ch == "1" …… or ch == "9" 2. 判斷字符串str是否是電話號碼(為簡單起見,現在只考慮固定電話號碼,也就是長度在7~8位之間的數字字符串,且第一位不為0) def isPhoneNum (str) : if len(str) >= 7 and len(str) <= 8 and str[0] != "0" : for ch in str : if not isDigit(ch) : return false return true return false 任務的復雜度并沒有增加太多,程序的復雜度增加了很多倍;如果你不同意,那么,來一個更復雜的。 3. 找出一段文本中所有的電話號碼 最直接的辦法是,在字符串中的每個位置截取7~8個字符,調用之前的isPhoneNum()。這么做看起來沒問題,只是效率太低。 當然,做點改進也不難,加上一個前置條件,只在“當前字符為數字字符”的情況下調用isPhoneNum()。這樣效率倒是改進了,但是還有問題沒有解決:要求找到的是長度大于等于7個字符、小于等于8個字符的“數字字符串”,而不是“子字符串”—也就是說,假如數字字符串是64240000,需要將它找出來;如果數字字符串是13800138000,則需要忽略它,以及其中的任何子串(比如13800138、00138000)。 所以,用isPhoneNum()找出字符串之后,還需要保證它之前的字符不是數字字符,之后的字符也不是數字字符。看起來很簡單,但合格的程序員一定要考慮邊界問題,避免越界錯誤:如果當前字符是整段文本的第一個字符,則不需要判斷之前的字符,因為它不存在;同樣,如果找出的字符串在整段文本的末尾,則不需要判斷之后的字符,因為它同樣不存在…… 到現在為止,即便只是找到最簡單的固定電話號碼,程序也非常復雜,難以維護。如果要查找的是形式更多變的文本,比如帶區號的電話號碼(021-64240000或者03718888888)、手機號碼(13800138000、+8613800138000或者013800138000),程序更是不可想象,更不用說文件路徑名、URL地址、電子郵件地址了!然而,日常開發中我們又確實經常需要面對這類任務,有什么更好的辦法呢? 正則表達式就是解決這類問題的萬能藥。雖然許多人有點看不起它,覺得不入流,一些科班教材里也不會花太多篇幅來介紹它,但它確實是解決問題的利器——之前提到的三個例子,用正則表達式都可以輕松解決。 引入正則表達式之后 1. 判斷字符ch是否是數字字符 def isDigit(ch) : return re.search(ch, "[0-9]") != None 看起來很復雜,其實并不復雜:這里真正要關心的就是正則表達式[0-9],它表示“從0到9之間的任意字符”,很形象吧?re.search()是正則表達式運算函數,它判斷ch能否由正則表達式[0-9]匹配,可以則返回一個結果,否則返回None(這些細節正文中會講到)。 2. 判斷字符串str是否是電話號碼 def isPhoneNum(str) : return re.search(str, "[1-9][0-9]{6,7}") != None 這個正則表達式最開始是[1-9],表示第一個字符必須是1~9之間的數字字符;之后是[0-9]{6,7},表示長度在6和7之間,由0~9之間的數字字符組成的字符串(兩部分加起來,整個字符串的長度在7和8之間)。要解決的問題復雜了,正則表達式仍然直觀形象。 3. 找出一段文本中所有的固定電話號碼 def findNumStr(str) : return re.findall(str, ‘(?<![0-9])[1-9][0-9]{6,7}(?![0-9])‘) 這個正則表達式之前多出了(?<![0-9]),表示“之前不能是[0-9]”;之后多出了(?![0-9]),表示“之后不能是[0-9]”。雖然稍微復雜點,但意思明確,而且不難理解。re.findall()的意思也很明顯:找到所有這樣的字符串。 可以想象,循著這種思路,查找更復雜的電話號碼、手機號碼等任務都不難解決。更重要的是,之前需要許多行語句才能完成的任務,現在基本上只需要一個正則表達式、一條語句就可以完成。正因為如此,不少人雖然認為正則表達式不夠花哨、漂亮,卻不得不承認它是一種“匕首應用”—匕首,沒有十八般兵刃那么氣派,關鍵時候卻不可或缺,所以值得花時間練練。同樣,正則表達式雖然不能用來顯擺,但總有派得上用場的地方,花時間練練絕不是壞事。即便你的工作不是純粹的文本處理(比如日志分析),也總會有用到正則表達式的地方(比如查找和修改源代碼),所以我希望,這本書能陪伴你練出一身正則表達式的好功夫,在關鍵場合能亮出稱手的工具。 最后,為了傳承經典教科書的良好習慣,附上正則表達式的“科班史”。 正則表達式發源于與計算機密切相關的兩個領域:計算理論和形式語言。20世紀40年代,兩位神經生理學家Warren McCulloch和Walter Pitts發明了一種用數學方式來描述神經網絡的辦法,他們把神經系統中的神經元描述成小而簡單的自動控制單元。1956年,數學家Stephen Cole Kleene在他們研究的基礎上,發表了一篇名為《神經網事件的表示法》的論文,在其中,他采用了一些稱之為“正則集合(regular set)”的數學符號來描述神經網絡模型。 之后,UNIX的主要發明人Ken Thompson將這個符號系統引入了文本編輯器QED(意思是“在文本中搜索某種模式”),正則表達式由此也進入了計算機世界。隨后Ken Thompson又將正則表達式引入了UNIX下的文本編輯器ed,ed最終演化為大家熟悉的grep(grep得名自ed編輯器中的正則表達式搜索命令g/re/p,其中的re表示“正則表達式”)。 返璞歸真——評《正則指引》 第一次接觸正則表達式,是2000年我在西安一家公司使用Perl做網站開發時。之前我在工作中只使用過標準的C語言,Perl這門編程語言的強大表達能力,令我印象極為深刻。Perl的力量,除了語言本身的設計之外,很大程度上來自它對正則表達式的完美支持。當時我們開發了一個網上商城的應用,允許很多商家在這里開店,可以選擇一些不同的樣式模板。我很快發現,使用Perl+正則表達式是開發這類應用的利器。我們只花了大約一個月的時間,就完成了網站核心功能的開發。那時候我意識到,使用正則表達式是聰明人寫程序的方法(沒說我是聰明人,但是我非常希望與那些聰明人為伍),可以極大地提高代碼的重用度和執行效率。如果完全不使用正則表達式,代碼量會增加數倍甚至數十倍。 后來因為一些原因,我告別了Perl。在之后的工作中,我使用過Java、JavaScript、Ruby等編程語言。我發現這些語言對于正則表達式的支持,沒有一個能夠超越Perl。Java這種所謂的“工業主流編程語言”,一直到2002年JDK 1.4推出時,才正式把對正則表達式的支持加入核心類庫。因為長期缺乏對正則表達式的原生支持,以及語言本身表達能力欠缺,使用Java來做大量的文本處理,感覺非常笨拙,完全沒有使用Perl那種指哪打哪的快感。直到2007年我發現了另一個更好的Perl語言—Ruby,才重新找回了2000年Perl帶給我的編程快感。 因為我的工作主要是做Web開發,大量的時間花在與HTML/CSS/JavaScript以及關系數據庫打交道上。在這里并沒有很高深的算法,只有大量繁重的文本處理。難以想象,如果沒有正則表達式,我們的開發將會是何等原始。 除了Web開發領域,需要實現大量自動化功能的一些領域,例如運維領域和自動化測試領域,也是正則表達式大顯身手的地方。無論使用稍顯簡陋的sed/awk還是更高級的Perl/Python/Ruby,實現自動化功能,都必須依賴大量的正則表達式。 自從面向對象的編輯方式時髦起來之后,甚至一度出現了面向對象萬能論,有人試圖用MDA和可執行的UML來解決一切編程問題。但是我一直認為面向對象只解決了軟件開發的一小部分問題,而且是宏觀方面的問題。正則表達式解決的問題,是面向對象無能為力的一些微觀方面的問題。在這里不需要坐而論道的方法論爭論,需要的是刺刀見紅的肉搏戰。這些問題即使使用完全面向對象的方式能夠解決,也會是很笨拙的。如果用物理學來比喻,面向對象是“廣義相對論”,而正則表達式則是“量子力學”。 正則表達式已經成為現代編程語言的基礎模塊,現在很難找到一種不支持正則表達式的編程語言。除了編程語言外,在很多工具軟件,例如文本編輯器(Vi、Emacs、UltraEdit)、Web服務器(Apache、Nginx)中都能找到正則表達式的身影。 余晟老師是我的朋友,我對他印象最為深刻的是他對于技術工作的嚴謹態度。“格物致知”是中國傳統儒家學派所追求的一種道德修養,也是一種境界。余老師是我的朋友中最接近“格物致知”這種境界的一位。我雖然從未精通過任何一門技術,但是很喜歡結交余老師這樣的朋友。 余老師潛心編著的這本《正則指引》深入淺出,將正則表達式的由來和分支娓娓道來。閱讀這本書,我仿佛回到了11年前做Perl程序員時的快樂時光。國內很多程序員的一個通病是好高騖遠,像《正則指引》這樣一本詳細講解基礎知識的書未必會有很好的銷路,但是等你做過很多年開發之后,你會發現,對你最有價值的,正是這些基礎知識和工具。軟件開發的“道”,正是隱藏在這些看起來不起眼的基礎知識和工具之中的。 李錕 2011年11月25日 克制我們內心的沖動 《正則指引(第2版)》就要出版了,按說這是一條好消息。在這條好消息面前,我更想做的是克制自己內心的沖動,靜下心來講講這本書初版以來的故事。 《正則指引》剛出版的時候,我一度認為,自己和正則表達式的緣分到此為止了。如果說翻譯《精通正則表達式》之后還有許多遺憾,比如某些講解方式不符合中國程序員的思維,以及過份關注英文,所以關于東亞文字處理的知識無從尋找,經驗無從分享。那么寫作《正則指引》,就是彌補這種缺憾的絕好機會。《正則指引》面世之后,這些缺憾已經悉數補上了。 令我沒有想到的是,《正則指引》自2012年出版以來,不斷有讀者向我反饋問題。除去最早一兩年密集熱烈的反饋,后續的反饋如涓涓細流綿綿不絕。而我一度想當然地認為勘誤已經完整了,所以一直沒檢查勘誤郵箱。直到一年前讀者在微信公眾號后臺給我留言,詳細列明勘誤意見之外,毫不留情地指責“對自己的作品不負責,長期不回復讀者意見”。這封信讓我慚愧不已。在軟件開發中,“發布了就不管”是很不負責的,在技術書籍的寫作中,“出版了兩年就不回復讀者意見”,同樣是很不負責的。 所以,我必須克制自己內心“年代久遠,不值得繼續打理”的偷懶沖動。文責自負,完整的說法應該是“文責終身自負”。 本次《正則指引(第2版)》的出版,對我而言是全新的補過機會,可以“一次性”回復迄今為止所有的讀者的意見。當然,新增的Objective-C、Golang等章節,盡管已經找熟悉的朋友審讀過,但我可以肯定,它們必定不是完美無瑕的,未來仍然需要坦然面對廣大讀者持續的批評指正。哪怕有些批評指正的語氣不那么讓人舒服,甚至“看不到幾分善意”,我仍然需要克制自己內心“反唇相譏”的沖動,認清事實,撇開情緒,虛心面對。 同時,我也希望讀者在閱讀這本書時,能克制自己內心的沖動。 我希望大家克制的第一重沖動,是淺嘗輒止—“正則表達式這玩意兒,要用時翻翻就好,沒必要深究”。正則表達式已經誕生的很多年了,以今天的標準來看,它的語法和結構相當粗陋,不幸的是,它的內部邏輯又相當復雜。有些朋友會問我一些“怎么看也看不懂”的正則表達式,坦白地說,我也要反復琢磨才能看懂。所以,盡管這本書提供了若干“速查”資料,但我還是建議讀者能耐下心來,至少通讀一遍。正則表達式有點像游泳,學會了就不會忘,用的時候自然能想起來。否則,你永遠只能在岸邊撲騰,離開了其他人的協助,一步都不敢往深處去。雖然很多時候,與你要的東西就只有一步之遙。 我希望大家克制的第二重沖動,是玩弄正則表達式的快感。前面說過,正則表達式的語法和結構相當粗陋,內部邏輯又相當復雜。所以不少人學會之后,產生了“掌握神奇魔咒”的快感。凡是和字符串相關的處理必亮出神奇的正則表達式,能用一個正則表達式的絕不用兩個,能用高級特性的絕不用簡單特性……隨之而來的,是其他人查錯時層出不窮的抱怨,更不用提更新時膽戰心驚的煩惱。要知道,熟練使用正則表達式,卻不濫用正則表達式,同時考慮合作同事的感受和效率,才能真正贏得大家的尊敬。 武學大師說:武功不是用來傷害,而是用來制止傷害的。哲學大師說:沒有審慎思考,不懂得克制的人生,是不值得過的。這些道理聽起來有悖常理,我花了不少時間才終于弄懂。我相信,正在閱讀這本書的你,也應當懂得這些道理。 特別感謝兩位女士,西喬和劉舫。西喬為這本書設計的封面,絲毫不受歲月的影響。劉舫編輯細致嚴謹的工作態度,支撐著我完成《正則指引》的第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列出了常用正則表達式的工具和資源,方便大家調試自己的正則表達式,以及繼續深入學習。 本書的讀者對象 本書適合以下幾類讀者: 經常需要進行文本處理(比如日志分析或網絡運維)的技術人員。這些讀者或許已經熟悉了正則表達式的基本用法,但面對日益復雜化和海量的數據,閱讀本書可以幫助大家更準確、更高效地處理文本,提升自己工作的價值。 熟悉常用開發語言的程序員。雖然這些讀者不需要專職進行文本處理,但源代碼和許多數據其實也是文本,如果不會正則表達式,在偶然遇到處理源代碼或文本數據的任務時,往往會產生無力感。本書的第三部分可以幫你快速找到有關的例子,并落實在自己的編程語言中。當然前兩部分也非常有必要,因為它們可以幫你夯實基礎。 對正則表達式已經有一定了解的讀者。這些讀者雖然能用正則表達式解決常見的問題,但未必了解正則表達式的編碼問題、匹配原理、解題思路,仔細閱讀本書的第二部分,可以深入完善對正則表達式的理解;而第三部分詳細比較了可以使用正則表達式的各種語言,以及同一種語言中各種版本的差異。所有這一切,應該可以讓你對正則表達式的掌握更上一層樓。 致謝 一本書的完成,離不開眾多人的幫忙。 首先要感謝的是李笑來老師、周筠老師以及徐定翔和盧鶇翔兩位編輯。在我翻譯完《精通正則表達式》之后,李笑來老師三番五次地鼓勵我寫一本關于正則表達式的書,并且打消了我的很多顧慮;周筠老師、徐定翔和盧鶇翔兩位編輯在我寫作的最初階段做了大量細致耐心的工作。可以說,沒有他們,我就不會有寫作這本書的念頭,也不會有堅持完成的動力。 然后要感謝的是電子工業出版社的楊福平副總編、張月萍編輯、張春雨編輯和劉舫編輯,沒有他們的關照和辛勤工作,這本書的出版定然會遇到更多的困難。 感謝我的朋友霍炬和韓磊,雖然我之前閱讀過《精通正則表達式》,但與翻譯和寫作結緣,他們給了我莫大的幫助,于是今天才有了《正則指引》這本書。尤其值得一提的是,霍炬的夫人西喬,精心手繪了這本書的封面,我在這里要對她表示誠摯的謝意。 感謝我曾工作過的盛大創新院以及創新院的各位同事(李駿、郝培強、莊表偉、丁宇、許式偉、莫華楓、李道兵、趙劼、樊一鵬、張一寧等),創新院給了大家寬松自由的工作環境,與各位同事的討論加深了我對正則表達式的理解,也為我提供了許多例子。 感謝張東亮、陸亦斌、孫勇、葉勁峰等各位朋友,愿意撥冗閱讀本書的草稿,并提出了大量專業的意見。 感謝何源、陳鋼、賀鈞、陳馳等讀者,試讀本書之后提出了大量的寶貴意見,在最后關頭打消了我心中的許多忐忑。 在更早之前,我的父母從小就鼓勵我研究和了解各種科學原理(“玩也要動腦筋”),我之所以有興趣探究正則表達式背后的世界,而不滿足于“夠用/湊合”,都是受益于這種思維行為習慣。在中小學階段,我的語文老師羅碧玉、易璽銘培養了我對于文字的興趣,在大學階段,東北師范大學文學院的王確老師給了我這個理科生非常多的幫助和指引。對各位師長,在此一并表示感謝,能遇到你們是我的幸運。 最后還需要感謝許多為這本書做出過貢獻的人,你們的名字我可能暫時無法記起,或者無法一一羅列,但我會在心中保持對你們的感謝。 |