mirror of
https://github.com/apachecn/ailearning.git
synced 2026-02-11 14:26:04 +08:00
271 lines
4.9 KiB
Markdown
271 lines
4.9 KiB
Markdown
# 正则表达式和 re 模块
|
||
|
||
## 正则表达式
|
||
|
||
[正则表达式](http://baike.baidu.com/view/94238.htm)是用来匹配字符串或者子串的一种模式,匹配的字符串可以很具体,也可以很一般化。
|
||
|
||
`Python` 标准库提供了 `re` 模块。
|
||
|
||
In [1]:
|
||
|
||
```py
|
||
import re
|
||
|
||
```
|
||
|
||
## re.match & re.search
|
||
|
||
在 `re` 模块中, `re.match` 和 `re.search` 是常用的两个方法:
|
||
|
||
```py
|
||
re.match(pattern, string[, flags])
|
||
re.search(pattern, string[, flags])
|
||
```
|
||
|
||
两者都寻找第一个匹配成功的部分,成功则返回一个 `match` 对象,不成功则返回 `None`,不同之处在于 `re.match` 只匹配字符串的开头部分,而 `re.search` 匹配的则是整个字符串中的子串。
|
||
|
||
## re.findall & re.finditer
|
||
|
||
`re.findall(pattern, string)` 返回所有匹配的对象, `re.finditer` 则返回一个迭代器。
|
||
|
||
## re.split
|
||
|
||
`re.split(pattern, string[, maxsplit])` 按照 `pattern` 指定的内容对字符串进行分割。
|
||
|
||
## re.sub
|
||
|
||
`re.sub(pattern, repl, string[, count])` 将 `pattern` 匹配的内容进行替换。
|
||
|
||
## re.compile
|
||
|
||
`re.compile(pattern)` 生成一个 `pattern` 对象,这个对象有匹配,替换,分割字符串的方法。
|
||
|
||
## 正则表达式规则
|
||
|
||
正则表达式由一些普通字符和一些元字符(metacharacters)组成。普通字符包括大小写的字母和数字,而元字符则具有特殊的含义:
|
||
|
||
| 子表达式 | 匹配内容 |
|
||
| --- | --- |
|
||
| `.` | 匹配除了换行符之外的内容 |
|
||
| `\w` | 匹配所有字母和数字字符 |
|
||
| `\d` | 匹配所有数字,相当于 `[0-9]` |
|
||
| `\s` | 匹配空白,相当于 `[\t\n\t\f\v]` |
|
||
| `\W,\D,\S` | 匹配对应小写字母形式的补 |
|
||
| `[...]` | 表示可以匹配的集合,支持范围表示如 `a-z`, `0-9` 等 |
|
||
| `(...)` | 表示作为一个整体进行匹配 |
|
||
| ¦ | 表示逻辑或 |
|
||
| `^` | 表示匹配后面的子表达式的补 |
|
||
| `*` | 表示匹配前面的子表达式 0 次或更多次 |
|
||
| `+` | 表示匹配前面的子表达式 1 次或更多次 |
|
||
| `?` | 表示匹配前面的子表达式 0 次或 1 次 |
|
||
| `{m}` | 表示匹配前面的子表达式 m 次 |
|
||
| `{m,}` | 表示匹配前面的子表达式至少 m 次 |
|
||
| `{m,n}` | 表示匹配前面的子表达式至少 m 次,至多 n 次 |
|
||
|
||
例如:
|
||
|
||
* `ca*t 匹配: ct, cat, caaaat, ...`
|
||
* `ab\d|ac\d 匹配: ab1, ac9, ...`
|
||
* `([^a-q]bd) 匹配: rbd, 5bd, ...`
|
||
|
||
## 例子
|
||
|
||
假设我们要匹配这样的字符串:
|
||
|
||
In [2]:
|
||
|
||
```py
|
||
string = 'hello world'
|
||
pattern = 'hello (\w+)'
|
||
|
||
match = re.match(pattern, string)
|
||
print match
|
||
|
||
```
|
||
|
||
```py
|
||
<_sre.SRE_Match object at 0x0000000003A5DA80>
|
||
|
||
```
|
||
|
||
一旦找到了符合条件的部分,我们便可以使用 `group` 方法查看匹配的部分:
|
||
|
||
In [3]:
|
||
|
||
```py
|
||
if match is not None:
|
||
print match.group(0)
|
||
|
||
```
|
||
|
||
```py
|
||
hello world
|
||
|
||
```
|
||
|
||
In [4]:
|
||
|
||
```py
|
||
if match is not None:
|
||
print match.group(1)
|
||
|
||
```
|
||
|
||
```py
|
||
world
|
||
|
||
```
|
||
|
||
我们可以改变 string 的内容:
|
||
|
||
In [5]:
|
||
|
||
```py
|
||
string = 'hello there'
|
||
pattern = 'hello (\w+)'
|
||
|
||
match = re.match(pattern, string)
|
||
if match is not None:
|
||
print match.group(0)
|
||
print match.group(1)
|
||
|
||
```
|
||
|
||
```py
|
||
hello there
|
||
there
|
||
|
||
```
|
||
|
||
通常,`match.group(0)` 匹配整个返回的内容,之后的 `1,2,3,...` 返回规则中每个括号(按照括号的位置排序)匹配的部分。
|
||
|
||
如果某个 `pattern` 需要反复使用,那么我们可以将它预先编译:
|
||
|
||
In [6]:
|
||
|
||
```py
|
||
pattern1 = re.compile('hello (\w+)')
|
||
|
||
match = pattern1.match(string)
|
||
if match is not None:
|
||
print match.group(1)
|
||
|
||
```
|
||
|
||
```py
|
||
there
|
||
|
||
```
|
||
|
||
由于元字符的存在,所以对于一些特殊字符,我们需要使用 `'\'` 进行逃逸字符的处理,使用表达式 `'\\'` 来匹配 `'\'` 。
|
||
|
||
但事实上,`Python` 本身对逃逸字符也是这样处理的:
|
||
|
||
In [7]:
|
||
|
||
```py
|
||
pattern = '\\'
|
||
print pattern
|
||
|
||
```
|
||
|
||
```py
|
||
\
|
||
|
||
```
|
||
|
||
因为逃逸字符的问题,我们需要使用四个 `'\\\\'` 来匹配一个单独的 `'\'`:
|
||
|
||
In [8]:
|
||
|
||
```py
|
||
pattern = '\\\\'
|
||
path = "C:\\foo\\bar\\baz.txt"
|
||
print re.split(pattern, path)
|
||
|
||
```
|
||
|
||
```py
|
||
['C:', 'foo', 'bar', 'baz.txt']
|
||
|
||
```
|
||
|
||
这样看起来十分麻烦,好在 `Python` 提供了 `raw string` 来忽略对逃逸字符串的处理,从而可以这样进行匹配:
|
||
|
||
In [9]:
|
||
|
||
```py
|
||
pattern = r'\\'
|
||
path = r"C:\foo\bar\baz.txt"
|
||
print re.split(pattern, path)
|
||
|
||
```
|
||
|
||
```py
|
||
['C:', 'foo', 'bar', 'baz.txt']
|
||
|
||
```
|
||
|
||
如果规则太多复杂,正则表达式不一定是个好选择。
|
||
|
||
## Numpy 的 fromregex()
|
||
|
||
In [10]:
|
||
|
||
```py
|
||
%%file test.dat
|
||
1312 foo
|
||
1534 bar
|
||
444 qux
|
||
|
||
```
|
||
|
||
```py
|
||
Writing test.dat
|
||
|
||
```
|
||
|
||
```py
|
||
fromregex(file, pattern, dtype)
|
||
```
|
||
|
||
`dtype` 中的内容与 `pattern` 的括号一一对应:
|
||
|
||
In [11]:
|
||
|
||
```py
|
||
pattern = "(\d+)\s+(...)"
|
||
dt = [('num', 'int64'), ('key', 'S3')]
|
||
|
||
from numpy import fromregex
|
||
output = fromregex('test.dat', pattern, dt)
|
||
print output
|
||
|
||
```
|
||
|
||
```py
|
||
[(1312L, 'foo') (1534L, 'bar') (444L, 'qux')]
|
||
|
||
```
|
||
|
||
显示 `num` 项:
|
||
|
||
In [12]:
|
||
|
||
```py
|
||
print output['num']
|
||
|
||
```
|
||
|
||
```py
|
||
[1312 1534 444]
|
||
|
||
```
|
||
|
||
In [13]:
|
||
|
||
```py
|
||
import os
|
||
os.remove('test.dat')
|
||
|
||
``` |