正则表达式.md 9.7 KB
Newer Older
C
CyC2018 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
<!-- GFM-TOC -->
* [一、概述](#一概述)
* [二、匹配单个字符](#二匹配单个字符)
* [三、匹配一组字符](#三匹配一组字符)
* [四、使用元字符](#四使用元字符)
* [五、重复匹配](#五重复匹配)
* [六、位置匹配](#六位置匹配)
* [七、使用子表达式](#七使用子表达式)
* [八、回溯引用](#八回溯引用)
* [九、前后查找](#九前后查找)
* [十、嵌入条件](#十嵌入条件)
* [参考资料](#参考资料)
<!-- GFM-TOC -->


# 一、概述

正则表达式用于文本内容的查找和替换。

正则表达式内置于其它语言或者软件产品中,它本身不是一种语言或者软件。

[正则表达式在线工具](https://regexr.com/)

# 二、匹配单个字符

**.**  可以用来匹配任何的单个字符,但是在绝大多数实现里面,不能匹配换行符;

**.**  是元字符,表示它有特殊的含义,而不是字符本身的含义。如果需要匹配 . ,那么要用 \ 进行转义,即在 . 前面加上 \ 

正则表达式一般是区分大小写的,但是也有些实现是不区分。

**正则表达式** 

```
nam.
```

**匹配结果** 

My  **name**  is Zheng.

# 三、匹配一组字符

**[ ]**  定义一个字符集合;

0-9、a-z 定义了一个字符区间,区间使用 ASCII 码来确定,字符区间在 [ ] 中使用。

**-**  只有在 [ ] 之间才是元字符,在 [ ] 之外就是一个普通字符;

**^**  在 [ ] 中是取非操作。

**应用** 

匹配以 abc 为开头,并且最后一个字母不为数字的字符串:

**正则表达式** 

```
abc[^0-9]
```

**匹配结果** 

1.  **abcd** 
2. abc1
3. abc2

# 四、使用元字符

## 匹配空白字符

|  元字符 | 说明  |
| :---: | :---: |
|  [\b] | 回退(删除)一个字符   |
|  \f |  换页符 |
|  \n |  换行符 |
|  \r |  回车符 |
|  \t |  制表符 |
|  \v |  垂直制表符 |

\r\n 是 Windows 中的文本行结束标签,在 Unix/Linux 则是 \n

\r\n\r\n 可以匹配 Windows 下的空白行,因为它匹配两个连续的行尾标签,而这正是两条记录之间的空白行;

## 匹配特定的字符类别

### 1. 数字元字符

|  元字符 | 说明  |
| :---: | :---: |
| \d  | 数字字符,等价于 [0-9]  |
| \D  | 非数字字符,等价于 [^0-9]   |

### 2. 字母数字元字符

|  元字符 | 说明  |
| :---: | :---: |
| \w  |  大小写字母,下划线和数字,等价于 [a-zA-Z0-9\_] |
|  \W |  对 \w 取非 |

### 3. 空白字符元字符

| 元字符  | 说明  |
| :---: | :---: |
|  \s | 任何一个空白字符,等价于 [\f\n\r\t\v]  |
| \S  |  对 \s 取非  |

\x 匹配十六进制字符,\0 匹配八进制,例如 \x0A 对应 ASCII 字符 10,等价于 \n

# 五、重复匹配

-  **\+**  匹配 1 个或者多个字符
W
weida zhong 已提交
113
-  **\*** 匹配 0 个或者多个
C
CyC2018 已提交
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
-  **?**  匹配 0 个或者 1 个

**应用** 

匹配邮箱地址。

**正则表达式** 

```
[\w.]+@\w+\.\w+
```

[\w.] 匹配的是字母数字或者 . ,在其后面加上 + ,表示匹配多次。在字符集合 [ ] 里,. 不是元字符;

**匹配结果** 

**abc.def<span>@</span>qq.com** 

-  **{n}**  匹配 n 个字符
133
-  **{m,n}**  匹配 m\~n 个字符
C
CyC2018 已提交
134 135
-  **{m,}**  至少匹配 m 个字符

136
\* 和 + 都是贪婪型元字符,会匹配尽可能多的内容。在后面加 ? 可以转换为懒惰型元字符,例如 \*?、+? 和 {m,n}? 。
C
CyC2018 已提交
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175

**正则表达式** 

```
a.+c
```

由于 + 是贪婪型的,因此 .+ 会匹配更可能多的内容,所以会把整个 abcabcabc 文本都匹配,而不是只匹配前面的 abc 文本。用懒惰型可以实现匹配前面的。

**匹配结果** 

**abcabcabc** 

# 六、位置匹配

## 单词边界

**\b**  可以匹配一个单词的边界,边界是指位于 \w\W 之间的位置;**\B** 匹配一个不是单词边界的位置。

\b 只匹配位置,不匹配字符,因此 \babc\b 匹配出来的结果为 3 个字符。

## 字符串边界

**^**  匹配整个字符串的开头,**$** 匹配结尾。

^ 元字符在字符集合中用作求非,在字符集合外用作匹配字符串的开头。

分行匹配模式(multiline)下,换行被当做字符串的边界。

**应用** 

匹配代码中以 // 开始的注释行

**正则表达式** 

```
^\s*\/\/.*$
```

C
CyC2018 已提交
176
<div align="center"> <img src="pics/600e9c75-5033-4dad-ae2b-930957db638e.png"/> </div><br>
C
CyC2018 已提交
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392

**匹配结果** 

1. public void fun() {
2. &nbsp;&nbsp;&nbsp;&nbsp;     **// 注释 1** 
3. &nbsp;&nbsp;&nbsp;&nbsp;    int a = 1;
4. &nbsp;&nbsp;&nbsp;&nbsp;    int b = 2;
5. &nbsp;&nbsp;&nbsp;&nbsp;     **// 注释 2** 
6. &nbsp;&nbsp;&nbsp;&nbsp;    int c = a + b;
7. }

# 七、使用子表达式

使用  **( )**  定义一个子表达式。子表达式的内容可以当成一个独立元素,即可以将它看成一个字符,并且使用 * 等元字符。

子表达式可以嵌套,但是嵌套层次过深会变得很难理解。

**正则表达式** 

```
(ab){2,}
```

**匹配结果** 

**ababab** 

**|**  是或元字符,它把左边和右边所有的部分都看成单独的两个部分,两个部分只要有一个匹配就行。

**正则表达式** 

```
(19|20)\d{2}
```

**匹配结果** 

1.  **1900** 
2.  **2010** 
3. 1020

**应用** 

匹配 IP 地址。

IP 地址中每部分都是 0-255 的数字,用正则表达式匹配时以下情况是合法的:

- 一位数字
- 不以 0 开头的两位数字
- 1 开头的三位数
- 2 开头,第 2 位是 0-4 的三位数
- 25 开头,第 3 位是 0-5 的三位数

**正则表达式** 

```
((25[0-5]|(2[0-4]\d)|(1\d{2})|([1-9]\d)|(\d))\.){3}(25[0-5]|(2[0-4]\d)|(1\d{2})|([1-9]\d)|(\d))
```

**匹配结果** 

1.  **192.168.0.1** 
2. 00.00.00.00
3. 555.555.555.555

# 八、回溯引用

回溯引用使用  **\n**  来引用某个子表达式,其中 n 代表的是子表达式的序号,从 1 开始。它和子表达式匹配的内容一致,比如子表达式匹配到 abc,那么回溯引用部分也需要匹配 abc 。

**应用** 

匹配 HTML 中合法的标题元素。

**正则表达式** 

\1 将回溯引用子表达式 (h[1-6]) 匹配的内容,也就是说必须和子表达式匹配的内容一致。

```
<(h[1-6])>\w*?<\/\1>
```

**匹配结果** 

1.  **&lt;h1>x&lt;/h1>** 
2.  **&lt;h2>x&lt;/h2>** 
3. &lt;h3>x&lt;/h1>

## 替换

需要用到两个正则表达式。

**应用** 

修改电话号码格式。

**文本** 

313-555-1234

**查找正则表达式** 

```
(\d{3})(-)(\d{3})(-)(\d{4})
```

**替换正则表达式** 

在第一个子表达式查找的结果加上 () ,然后加一个空格,在第三个和第五个字表达式查找的结果中间加上 - 进行分隔。

```
($1) $3-$5
```

**结果** 

(313) 555-1234

## 大小写转换

|  元字符 | 说明  |
| :---: | :---: |
|  \l | 把下个字符转换为小写  |
|   \u| 把下个字符转换为大写  |
|  \L | 把\L\E 之间的字符全部转换为小写  |
|  \U | 把\U\E 之间的字符全部转换为大写  |
|  \E | 结束\L 或者\U  |

**应用** 

把文本的第二个和第三个字符转换为大写。

**文本** 

abcd

**查找** 

```
(\w)(\w{2})(\w)
```

**替换** 

```
$1\U$2\E$3
```

**结果** 

aBCd

# 九、前后查找

前后查找规定了匹配的内容首尾应该匹配的内容,但是又不包含首尾匹配的内容。向前查找用  **?=**  来定义,它规定了尾部匹配的内容,这个匹配的内容在 ?= 之后定义。所谓向前查找,就是规定了一个匹配的内容,然后以这个内容为尾部向前面查找需要匹配的内容。向后匹配用 ?<= 定义(注: javaScript 不支持向后匹配, java 对其支持也不完善)。

**应用** 

查找出邮件地址 @ 字符前面的部分。

**正则表达式** 

```
\w+(?=@)
```

**结果** 

**abc** @qq.com

对向前和向后查找取非,只要把 = 替换成 ! 即可,比如 (?=) 替换成 (?!) 。取非操作使得匹配那些首尾不符合要求的内容。

# 十、嵌入条件

## 回溯引用条件

条件判断为某个子表达式是否匹配,如果匹配则需要继续匹配条件表达式后面的内容。

**正则表达式** 

子表达式 (\\() 匹配一个左括号,其后的 ? 表示匹配 0 个或者 1 个。 ?(1) 为条件,当子表达式 1 匹配时条件成立,需要执行 \) 匹配,也就是匹配右括号。

```
(\()?abc(?(1)\))
```

**结果** 

1.  **(abc)** 
2.  **abc** 
3. (abc

## 前后查找条件

条件为定义的首尾是否匹配,如果匹配,则继续执行后面的匹配。注意,首尾不包含在匹配的内容中。

**正则表达式** 

 ?(?=-) 为前向查找条件,只有在以 - 为前向查找的结尾能匹配 \d{5} ,才继续匹配 -\d{4} 。

```
\d{5}(?(?=-)-\d{4})
```

**结果** 

1.  **11111** 
2. 22222-
3.  **33333-4444** 

# 参考资料

- BenForta. 正则表达式必知必会 [M]. 人民邮电出版社, 2007.




C
CyC2018 已提交
393
# 微信公众号
C
CyC2018 已提交
394 395


C
CyC2018 已提交
396
更多精彩内容将发布在微信公众号 CyC2018 上,你也可以在公众号后台和我交流学习和求职相关的问题。另外,公众号提供了该项目的 PDF 等离线阅读版本,后台回复 "下载" 即可领取。公众号也提供了一份技术面试复习大纲,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点,后台回复 "大纲" 即可领取。我基本是按照这个大纲来进行复习的,对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。
C
CyC2018 已提交
397 398


C
CyC2018 已提交
399
<br><div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/other/公众号海报6.png"></img></div>