3dwoo大學簡體電腦書店
正則指引(第2版)
( 簡體 字)
作者:余晟類別:1. -> 程式設計 -> 綜合
出版社:電子工業出版社正則指引(第2版) 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列出了常用正則表達式的工具和資源,方便大家調試自己的正則表達式,以及繼續深入學習。
本書的讀者對象
本書適合以下幾類讀者:
經常需要進行文本處理(比如日志分析或網絡運維)的技術人員。這些讀者或許已經熟悉了正則表達式的基本用法,但面對日益復雜化和海量的數據,閱讀本書可以幫助大家更準確、更高效地處理文本,提升自己工作的價值。
熟悉常用開發語言的程序員。雖然這些讀者不需要專職進行文本處理,但源代碼和許多數據其實也是文本,如果不會正則表達式,在偶然遇到處理源代碼或文本數據的任務時,往往會產生無力感。本書的第三部分可以幫你快速找到有關的例子,并落實在自己的編程語言中。當然前兩部分也非常有必要,因為它們可以幫你夯實基礎。
對正則表達式已經有一定了解的讀者。這些讀者雖然能用正則表達式解決常見的問題,但未必了解正則表達式的編碼問題、匹配原理、解題思路,仔細閱讀本書的第二部分,可以深入完善對正則表達式的理解;而第三部分詳細比較了可以使用正則表達式的各種語言,以及同一種語言中各種版本的差異。所有這一切,應該可以讓你對正則表達式的掌握更上一層樓。
致謝
一本書的完成,離不開眾多人的幫忙。
首先要感謝的是李笑來老師、周筠老師以及徐定翔和盧鶇翔兩位編輯。在我翻譯完《精通正則表達式》之后,李笑來老師三番五次地鼓勵我寫一本關于正則表達式的書,并且打消了我的很多顧慮;周筠老師、徐定翔和盧鶇翔兩位編輯在我寫作的最初階段做了大量細致耐心的工作。可以說,沒有他們,我就不會有寫作這本書的念頭,也不會有堅持完成的動力。
然后要感謝的是電子工業出版社的楊福平副總編、張月萍編輯、張春雨編輯和劉舫編輯,沒有他們的關照和辛勤工作,這本書的出版定然會遇到更多的困難。
感謝我的朋友霍炬和韓磊,雖然我之前閱讀過《精通正則表達式》,但與翻譯和寫作結緣,他們給了我莫大的幫助,于是今天才有了《正則指引》這本書。尤其值得一提的是,霍炬的夫人西喬,精心手繪了這本書的封面,我在這里要對她表示誠摯的謝意。
感謝我曾工作過的盛大創新院以及創新院的各位同事(李駿、郝培強、莊表偉、丁宇、許式偉、莫華楓、李道兵、趙劼、樊一鵬、張一寧等),創新院給了大家寬松自由的工作環境,與各位同事的討論加深了我對正則表達式的理解,也為我提供了許多例子。
感謝張東亮、陸亦斌、孫勇、葉勁峰等各位朋友,愿意撥冗閱讀本書的草稿,并提出了大量專業的意見。
感謝何源、陳鋼、賀鈞、陳馳等讀者,試讀本書之后提出了大量的寶貴意見,在最后關頭打消了我心中的許多忐忑。
在更早之前,我的父母從小就鼓勵我研究和了解各種科學原理(“玩也要動腦筋”),我之所以有興趣探究正則表達式背后的世界,而不滿足于“夠用/湊合”,都是受益于這種思維行為習慣。在中小學階段,我的語文老師羅碧玉、易璽銘培養了我對于文字的興趣,在大學階段,東北師范大學文學院的王確老師給了我這個理科生非常多的幫助和指引。對各位師長,在此一并表示感謝,能遇到你們是我的幸運。
最后還需要感謝許多為這本書做出過貢獻的人,你們的名字我可能暫時無法記起,或者無法一一羅列,但我會在心中保持對你們的感謝。
pagetop