## 正则表达式

### 动机
现如今文本处理已经成文计算机的主要工作之一。文字处理、网页填表、数据库的信息流处理等等。因为我们可能不知道这些需要计算机编程处理文本或数据的具体内容,所以能把这些文本或数据以某种可被计算机识别和处理的模式表达出来是非常有用的。而正则表达式正是处理文本的解决方案,它是可以匹配文本片段的一种模式。
正则表达式(RE)为高级文本模式匹配,以及搜索-替代等功能提供了基础。正则表达式(RE)是一些由字符和特殊符号组成的字符串,它们描述了这些字符和字符的某种重复方式,因此能按某种模式匹配一个有相似特征的字符串的 *** 。
#### 应用场景和解决的问题
- 通过编程使计算机具有在文本中检索某种模式的能力
- 正则表达式为高级的文本模式匹配、抽取、或文本形式的搜索和替换功能提供基础
- regex是一些由字符和特殊符号组成的字符串,它们描述了模式的重复或表述多个字符,于是regex能按照某种模式匹配一系列有相似特征的字符串
- 多种语言都提供了正则表达式接口,可以通过编程方便地处理正则表达式
- regex的强大之处在于引入特殊字符来定义字符集、匹配自组和重复模式
### 正则表达式使用的特殊符号和字符
下面我们来介绍最常用的元字符(metacharacters)——特殊字符和符号,正是它们赋予了正则表达式强大的功能和灵活性。
* literal
```
re.findall('abc','abcdef')
```
* re1 | re2
```
re.findall('ab|cd','abcdef')
```
* `.`
点号. 用于匹配除了换行符\n以外的任何字符
|regex模式 |匹配的字符串 |
| --- | --- |
|f.o |匹配在字母f和o之间的任意一个字符:fao,f9o,f#o等 |
|..|任意两个字符 |
|.end|匹配在字符串end之前的任意一个字符 |
注意:要匹配句点字符,用反斜线转义句点符号的功能 \"\.\"
```
re.findall('a.c','abcdef')
```
* `^ $`
|regex模式 |匹配的字符串 |
| --- | --- |
|^From |任何以From作为起始的字符串 |
|/bin/tcsh$|任何以/bin/tcsh作为结尾的字符串 |
|^Subject:hi$|任何由单独的字符串Subject:hi构成的字符串 |
注意:匹配任何以美元符号结尾的字符串,用 .*\$$
```
re.findall('^abc','abcdef')
re.findall('def$','abcdef')
```
* `*`
匹配其左边的regex出现零次或多次的情况
```
re.findall('ab*','abbbbbb')
```
* `+`
加号+:匹配一次或多次出现的正则表达式
```
re.findall('ab+','abbbbbbbb')
```
* `?`
匹配零次或一次出现的regex
```
re.findall('ab?','abbbbbb')
```
* {N}
```
re.findall('ab{3}','abbbbbbb')
```
* {M,N}
|regex模式 |匹配的字符串 |
| --- | --- |
|[0-9]{15,16} |匹配15或16个数字,例如信用卡号码 |
```
re.findall('ab{1,3}','abbbbbbbb')
```
* `[...]`
|regex模式 |匹配的字符串 |
| --- | --- |
|b[aeiu]t |bat, bet, bit, but等 |
|[cr][23][dp][o2] |c2do, r3p2等 |
```
re.findall('[abc]','abcdef')
```
* `[a-zA-Z0-9]`
|regex模式 |匹配的字符串 |
| --- | --- |
|z.[0-9] |字母z后面跟着任何一个字符,然后跟着一个数字 |
|[r-u][env-y][us] |字母r,s,t,或u,后面跟着e,n,v,w,x,或y, 然后跟着u或s |
|[^aeiou] |一个非元音字符|
|[^\t\n] |不匹配制表符或\n|
```
re.findall('[a-z]','abcdef')
```
* `[^...]`
```
re.findall('[^bcd]','abcdef')
```
* `\d \D`
|regex模式 |匹配的字符串 |
|\d{3}-\d{3}-\d{4} |美国 *** 号码的格式,如800-555-1212 |
```
re.findall('\d','12345')
```
* `\w \W`
|regex模式 |匹配的字符串 |
| --- | --- |
|\w+-\d+ |一个由字母数字组成的字符串,一个连字符,再加一串数字 |
|[A-Za-z]\w* |之一个字符是字母, 其余字符(如果存在)可以是字母或数字 |
|\w+@\w+\.com |以XXX@YYY.com格式表示的简单电子邮件地址 |
```
re.findall('\w','abcdef')
```
* `\s \S`
```
re.findall('\s','a b c\n')
```
* `\b \B`
|regex模式 |匹配的字符串 |
| --- | --- |
|the |任何包含the的字符串 |
|\bthe |任何以the开始的字符串 |
|\bthe\b |仅仅匹配单词the |
|\Bthe |任何包含但并不以the作为起始的字符串 |
```
re.findall(r'\bgame\b','game over')
```
* `\A \Z`
```
re.findall('\Aabc\Z','abc')
```
## raw字符串
正则表达式用反斜杠字符 (\"\\") 来表示特殊格式或允许使用特殊字符而不调用它的特殊用法。这就与 Python 在字符串中的那些起相同作用的相同字符产生了冲突。让我们举例说明,你想写一个 RE 以匹配字符串 \"\section\",可能是在一个文件查找。为了要在程序代码中判断,首先要写出想要匹配的字符串。接下来你需要在所有反斜杠和其它元字符前加反斜杠来取消其特殊意义,结果要匹配的字符串就成了\"\\section\"。 当把这个字符串传递给re.compile()时必须还是\"\\section\"。然而,作为Python的字符串实值(string literals)来表示的话,\"\\section\"中两个反斜杠还要再次取消特殊意义,最后结果就变成
了\"\\\\section\"。
简单地说,为了匹配一个反斜杠,不得不在 RE 字符串中写 '\\\\',因为正则表达式中必须是 \"\\\",而每个反斜杠在常规的 Python 字符串实值中必须表示成
\"\\\"。在REs中反斜杠的这个重复特性会导致大量重复的反斜杠,而且所生成的字符串也很难懂。解决的办法就是为正则表达式使用 Python 的 raw 字符串表示;在字符串前加个\"r\" 反斜杠就不会被任何特殊方式处理,所以 r\"\n\" 就是包含\"\\"和\"n\"的两个字符,而\"\n\"则是一个字符,表示一个换行。正则表达式通常在 Python 代码中都是用这种 raw 字符串表示。
## 贪婪模式和非贪婪模式
贪婪和非贪婪是针对正则表达式中 `* + {N} {M,N} ?` 这几种匹配而言的。在使用的时候默认是贪婪模式,即总是尽可能的匹配更多的内容。例如,当重复一个正则表达式时,如用 a*,操作结果是尽可能多地匹配模式。当你试着匹配一对对称的定界符,如 HTML 标志中的尖括号时这个事实经常困扰你。匹配单个 HTML 标志的模式不能正常工作,因为 .* 的本质是“贪婪”的
在这种情况下,解决方案是使用不贪婪的限定符 `*?、+?、??` 或 `{m,n}?`,尽可能匹配小的文本。
```
re.findall('a*?','abcdef')
```
## 正则表达式分组
组是通过 \"(\" 和 \")\" 元字符来标识的。 \"(\" 和 \")\" 有很多在数学表达式中相同的意思;它们一起把在它们里面的表达式组成一组。举个例子,你可以用重复限制符,像` *, +, ?, 和 {m,n}`,来重复组里的内容,比如说(ab)* 将匹配零或更多个重复的 \"ab\"。
|regex模式 |匹配的字符串 |
| --- | --- |
|\d+(\.\d*)? |任何十进制数字,接一个小数点和零个或多个十进制数字,如0.004,2,75.1 |
|(Mr?s?\.)?[A-Z][a-z]*\s[A-Za-z]+ | |
### 分组命名
精心设计的 REs 也许会用很多组,既可以捕获感兴趣的子串,又可以分组和结构化 RE 本身。在复杂的 REs 里,追踪组号变得困难。开发人员的解决 *** 是使用 (?...) 来做为扩展语法。Python 新增了一个扩展语法到 Perl 扩展语法中。如果在问号后的之一个字符是 \"P\",你就可以知道它是针对 Python 的扩展。目前有两个这样的扩展: (?
P
```
re.findall(r'(?P
re.findall(r'(?P
```
正则表达式生成神器 正则表达式入门必知必会