正则表达式是用来匹配字符串或者子串的一种模式,匹配的字符串可以很具体,也可以很一般化。
Python
标准库提供了 re
模块。
In [1]:
import re
在 re
模块中, re.match
和 re.search
是常用的两个方法:
re.match(pattern, string[, flags])
re.search(pattern, string[, flags])
两者都寻找第一个匹配成功的部分,成功则返回一个 match
对象,不成功则返回 None
,不同之处在于 re.match
只匹配字符串的开头部分,而 re.search
匹配的则是整个字符串中的子串。
re.findall(pattern, string)
返回所有匹配的对象, re.finditer
则返回一个迭代器。
re.split(pattern, string[, maxsplit])
按照 pattern
指定的内容对字符串进行分割。
re.sub(pattern, repl, string[, count])
将 pattern
匹配的内容进行替换。
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]:
string = 'hello world'
pattern = 'hello (\w+)'
match = re.match(pattern, string)
print match
<_sre.SRE_Match object at 0x0000000003A5DA80>
一旦找到了符合条件的部分,我们便可以使用 group
方法查看匹配的部分:
In [3]:
if match is not None:
print match.group(0)
hello world
In [4]:
if match is not None:
print match.group(1)
world
我们可以改变 string 的内容:
In [5]:
string = 'hello there'
pattern = 'hello (\w+)'
match = re.match(pattern, string)
if match is not None:
print match.group(0)
print match.group(1)
hello there
there
通常,match.group(0)
匹配整个返回的内容,之后的 1,2,3,...
返回规则中每个括号(按照括号的位置排序)匹配的部分。
如果某个 pattern
需要反复使用,那么我们可以将它预先编译:
In [6]:
pattern1 = re.compile('hello (\w+)')
match = pattern1.match(string)
if match is not None:
print match.group(1)
there
由于元字符的存在,所以对于一些特殊字符,我们需要使用 '\'
进行逃逸字符的处理,使用表达式 '\\'
来匹配 '\'
。
但事实上,Python
本身对逃逸字符也是这样处理的:
In [7]:
pattern = '\\'
print pattern
\
因为逃逸字符的问题,我们需要使用四个 '\\\\'
来匹配一个单独的 '\'
:
In [8]:
pattern = '\\\\'
path = "C:\\foo\\bar\\baz.txt"
print re.split(pattern, path)
['C:', 'foo', 'bar', 'baz.txt']
这样看起来十分麻烦,好在 Python
提供了 raw string
来忽略对逃逸字符串的处理,从而可以这样进行匹配:
In [9]:
pattern = r'\\'
path = r"C:\foo\bar\baz.txt"
print re.split(pattern, path)
['C:', 'foo', 'bar', 'baz.txt']
如果规则太多复杂,正则表达式不一定是个好选择。
In [10]:
%%file test.dat
1312 foo
1534 bar
444 qux
Writing test.dat
fromregex(file, pattern, dtype)
dtype
中的内容与 pattern
的括号一一对应:
In [11]:
pattern = "(\d+)\s+(...)"
dt = [('num', 'int64'), ('key', 'S3')]
from numpy import fromregex
output = fromregex('test.dat', pattern, dt)
print output
[(1312L, 'foo') (1534L, 'bar') (444L, 'qux')]
显示 num
项:
In [12]:
print output['num']
[1312 1534 444]
In [13]:
import os
os.remove('test.dat')