## 第?26?章?正則表達式
**目錄**
[](ch26.html#id3119846)
[簡介](ch26s02.html)
[運算優先級](ch26s03.html)
[轉義符](ch26s04.html)
[字符類](ch26s05.html)
[限定符](ch26s06.html)
[貪婪與懶惰](ch26s06.html#id3120652)
[分支條件](ch26s07.html)
[分組、捕獲](ch26s08.html)
[分組](ch26s08.html#id3120847)
[捕獲](ch26s08.html#id3120909)
[零寬斷言](ch26s09.html)
[負向零寬斷言](ch26s09.html#id3121214)
## 簡介
對于文本內容的處理,通常使用交互方式,手工調整;但如果你對源文本比較了解,則可以采用自動化的批量處理方式,這種方式效率高、迅速快
批量處理,要求根據一定規則,匹配源文本中的字符,轉換為目標文本,這就要用到正則表達式
最簡單的例子,使用`regular`進行匹配,結果如下:
```
`regular` expression
```
正則表達式有許多變種:glob 表達式、基本正則表達式、perl 正則表達式、emacs 正則表達式……
如[“通配符”一節](ch14s06.html#glob "通配符")中介紹的為最簡單的 glob 表達式
## 運算優先級
正則表達式與數學表達式的不同在于,數學表達式執行數學運算,而正則表達式執行字符運算;相同的是,它們都按一定的優先級進行運算
| 運算符 | 操作 |
| --- | --- |
| \ | 轉義符 |
| () | 捕獲、匹配、斷言 |
| [] | 字符類 |
| *+? | 限定符 |
| {} | 范圍 |
| ^$ | 位置和順序 |
| | | 或 |
## 轉義符
如果源文本中出現了正則表達式中的運算符,如`(`,使用 `(` 無法匹配下列文本中的括弧,這時要使用 `\` 進行轉義。用 `\(`匹配[[48](ch26s04.html#ftn.id3119995)]:
```
`(`regular expression)
```
在文本中匹配[“運算優先級”一節](ch26s03.html "運算優先級")中的所有運算符,都要用這種形式:
```
\運算符
```
在文本中匹配`\`本身,要用 `\\`
非運算符前使用 `\` ,則有特殊的意義,例如`\n`匹配一個換行符。常用轉義字符:
| 轉義字符 | 涵義 |
| --- | --- | --- |
| 常規匹配 | . | 匹配除換行符以外的任意字符 |
| \w | 匹配字母或數字或下劃線或漢字 |
| \s | 匹配任意的空白符 |
| \d | 匹配數字 |
| \b | 匹配單詞的開始或結束,在字符類里代表退格 |
| ^ | 匹配字符串的開始,在字符類里表示”非“ |
| $ | 匹配字符串的結束 |
| 反向匹配 | \W | 匹配任意不是字母,數字,下劃線,漢字的字符 |
| \S | 匹配任意不是空白符的字符 |
| \D | 匹配任意非數字的字符 |
| \B | 匹配不是單詞開頭或結束的位置 |
| [^aeiou] | 匹配除了 aeiou 這幾個字母以外的任意字符 |
| 特殊字符 | \a | 報警字符(打印它的效果是電腦嘀一聲) |
| \t | 制表符,Tab |
| \r | 回車 |
| \v | 垂直制表符 |
| \f | 換頁符 |
| \n | 換行符 |
| \e | Escape |
| \0nn | ASCII 代碼中八進制代碼為 nn 的字符 |
| \xnn | ASCII 代碼中十六進制代碼為 nn 的字符 |
| \unnnn | Unicode 代碼中十六進制代碼為 nnnn 的字符 |
| \cN | ASCII 控制字符。比如 \cC 代表 Ctrl+C |
| \A | 字符串開頭(類似^,但不受處理多行選項的影響) |
| \Z | 字符串結尾或行尾(不受處理多行選項的影響) |
| \z | 字符串結尾(類似$,但不受處理多行選項的影響) |
| \G | 當前搜索的開頭 |
* * *
> [[48](ch26s04.html#id3119995)] 在 Emacs 和 Vim 正則表達式中正好反過來,使用`\(`表示分組,用`(`匹配字符
## 字符類
要想匹配數字、字母、空白很容易,因為已經有了對應這些字符集合的轉義符,但是如果你想匹配沒有預定義的字符集合(比如元音字母 a、e、i、o、u),應該怎么辦?
正則表達式中允許你自定義字符類,在方括號里列出它們就可以了
```
[aeiou]
```
預定義的字符集合,也可以用字符類表示,如 `\d` 等價于 `[0-9]`
有些運算符,在字符類中使用會有另一種意義,例如`^`表示“字符串開始”,但在字符類中卻表示 “非”,以`expression`為例,使用`[exp]`匹配:
```
`exp`r`e`ssion
```
使用`[^exp]`匹配(字符串中非 e、x、p 的字符):
```
exp`r`e`ssion`
```
而使用`^[exp]`匹配(以 e、x 或 p 起始的字符串):
```
`e`xpression
```
## 限定符
在上一小節中的表格中,我們知道 `.` 可以匹配除換行符以外的任意字符,使用`.`匹配下列文本:
```
expression
```
但是`.`每次只匹配一個字符,如果想一次匹配多個,則要使用限定符
| 限定符 | 作用 |
| --- | --- |
| * | 匹配零次或多次 |
| + | 匹配一次或多次 |
| ? | 匹配零次或一次 |
| {3} | 匹配三次 |
| {3,5} | 匹配三到五次 |
| {3,} | 匹配三次或以上 |
下面通過實例了解限定符的區別。 `es` 的匹配結果
```
expr`es`sion
```
`es+` 的匹配結果(e,一個或多個 s)
```
expr`ess`ion
```
`es*` 的匹配結果(e,零或多個 s)
```
`e`xpr`ess`ion
```
`es?` 的匹配結果(e,零或一個 s)
```
`e`xpr`es`sion
```
### 貪婪與懶惰
使用限定符進行匹配時,默認匹配盡可能多的字符。無論用 `.*` 還是 `.+` 匹配下列文本,都會匹配全部
```
`expression`
```
這種方式稱為“貪婪模式”。在限定符之后加 `?` 則匹配盡可能少的字符,稱為“懶惰模式”[[49](ch26s06.html#ftn.id3120698)]
例如,使用貪婪模式`a.+b`匹配:
```
`aaabab`
```
使用懶惰模式`a.+?b`匹配:
```
`aaab`ab
```
* * *
> [[49](ch26s06.html#id3120698)] `.+` 匹配一個或多個任意字符,在貪婪模式中,它匹配盡可能多的字符;而懶惰模式中(`.+?`),則只匹配一個字符;`.{3,5}`在貪婪模式中盡可能匹配5個字符,在懶惰模式中(`.{3,5}?`)只匹配3個字符;`?` 和 `*` 這樣可以匹配零次的限定符,在懶惰模式下不匹配任何字符(`.*?`、`.??`)
## 分支條件
`|` 表示“或”,使用它進行分支選擇
例如`[a-z]+|\d+`匹配單詞或數字:
```
expression 123
```
## 分組、捕獲
### 分組
使用`(表達式)`對表達式進行分組,例如使用`(\d{3}\.){2}`匹配下面例子中的數字:
```
abc`123.456.`def
```
`\d{3}`表示三個數字,`(\d{3}\.)`表示三個數字加“`.`”為一組,`{2}`表示這一組內容重復兩次
### 捕獲
在對表達式進行分組的時候,會捕獲文本到自動命名的組里,使用 `\1 \2 ……` 后向引用組
例如用`([a-z]*)\ (\d*)`匹配下列文本,`([a-z]*)`為`\1`組,`(\d*)`為`\2`組
```
kardinal 1234567
```
使用`\2\ \1`替換`([a-z]*)\ (\d*)`,可以改變兩個字符串的順序
```
1234567 kardinal
```
如果分組較多,計數可能會不太方便,可以給分組指定名稱,例如:
```
(?<**name**>[a-z]*)\ (?<**num**>\d*)
\k<**num**>\ \k<**name**> (?#使用“`\k<name>`”后向引用)
```
使用`(?:表達式)`,則只是分組,而不捕獲,下面例子中,`(\d*)`為`\1`組
```
(?:[a-z]*)\ (\d*)
```
## 零寬斷言
目前為止,我們學到的正則表達式匹配,都是有“寬度”的,使用 `\w+。` 匹配下面文本,會將 `。` 一同匹配:
```
regular。
expression。
```
如果不想匹配符號,只匹配一個位置,就要用到“零寬斷言”(匹配寬度為零,滿足一定的 條件/斷言),零寬斷言使用 **(?=表達式)** 的語法,例如 `\w+(?=。)`,其中 `(?=。)` 表示 `。` 前面的位置(先行斷言)
```
`regular`。
`expression`。
```
如果需要匹配后面的位置,如:
```
。`regular`
。`expression`
```
則要用到后發斷言 `(?<=。)` ,使用 `(?<=。)\w+` 得到上面的匹配結果
使用 `(?<=<b>).*(?=</b>)` 匹配標簽中的內容
```
<b>`粗體`</b>
```
### 負向零寬斷言
負向零寬斷言 **(?!表達式)** 也是匹配一個零寬度的位置,不過這個位置的“斷言”取表達式的反值,例如 `(?!表達式)` 表示 `表達式` 前面的位置,如果 `表達式` 不成立 ,匹配這個位置;如果 `表達式` 成立,則不匹配:
```
`expression`
`expression`,
`expression`;
expression。
```
以上為使用 `.+n(?!。)` 的匹配結果。注意與 `.+n[^。]` 匹配的區別
```
expression
`expression,`
`expression;`
expression。
```
同樣,負向零寬斷言也有“先行”和“后發”兩種,負向零寬后發斷言為 **(?<!表達式)**
使用 `(?<![</])para(?!>)` 匹配下面文本
```
<para>`para`表示一個段落</para>
```
* `(?<![</])` 表示 `para` 左邊不能為 `<` 或 `/` ;`(?!>)` 表示 `para` 右邊不能為 `>`
- 開源世界旅行手冊
- 授權
- 致謝
- 序言
- 更新紀錄
- 導讀
- 如何寫作科技文檔
- 部分?I.?氣候
- 第?1?章?GUI? CLI?
- 第?2?章?UNIX 縮寫風格
- 第?3?章?版本號的迷霧
- 第?4?章???Vim 還是 Emacs
- 第?5?章???DocBook 還是 TeX
- 第?6?章?完全用 Gnu/Linux 工作
- 第?7?章?病毒
- 第?8?章?磁盤 分區
- 第?9?章?文件系統
- 第?10?章???發行版介紹
- 第?11?章???編程語言
- 第?12?章?無根的根:無名師的 Unix 心傳
- 部分?II.?地理
- 第?13?章?基礎知識
- 第?14?章?命令系統
- 第?15?章?基本系統
- 第?16?章?軟件管理
- 第?17?章?核心工具集
- 第?18?章?編譯工具鏈
- 第?19?章?圖形界面
- 第?20?章?國際化
- 第?21?章???內核
- 第?22?章?Grub
- 第?23?章?服務器
- 第?24?章?Vim 編輯器
- 第?25?章?Emacs 入門
- 第?26?章?正則表達式
- 第?27?章?docbook 指南
- 第?28?章?Git 版本控制系統
- 第?29?章?ConTeXt 入門指南
- 部分?III.?景觀
- 第?30?章?終極 Shell -- ZSH
- 第?31?章?完美工作站 Archlinux
- 第?32?章?組織你的意念:Emacs org mode
- 第?33?章???Zsh+screen
- 第?34?章???gentoo stage3
- 第?35?章???硬件問題
- 第?36?章???網絡設置
- 第?37?章???自制 LiveCD
- 第?38?章?awesome
- 第?39?章?openbox 工作環境
- 第?40?章???Emacs muse
- 第?41?章???寫作工具鏈
- 第?42?章?使用 lftp
- 第?43?章???Firefox 使用技巧
- 第?44?章???FVWM
- 部分?IV.?地質
- 第?45?章?Unix
- 第?46?章???Gnu
- 第?47?章?軟件業自由之神——Richard Stallman
- 第?48?章?Linux
- 第?49?章?GNOME與KDE的戰爭
- 第?50?章???Vim Emacs
- 第?51?章???年代紀
- 第?52?章?我的選擇
- 第?53?章???補遺