python_正则表达式

正则表达式

正则表达式(称为RE,或正则,或正则表达式模式)本质上是嵌入在Python中的一种微小的、高度专业化的编程语言,可通过 re 模块获得。 使用这种小语言,你可以为要匹配的可能字符串集指定规则;此集可能包含英语句子,电子邮件地址,TeX命令或你喜欢的任何内容。 然后,您可以询问诸如“此字符串是否与模式匹配?”或“此字符串中的模式是否匹配?”等问题。 你还可以使用正则修改字符串或以各种方式将其拆分。
正则表达式模式被编译成一系列字节码,然后由用 C 编写的匹配引擎执行。对于高级用途,可能需要特别注意引擎如何执行给定的正则,并将正则写入以某种方式生成运行速度更快的字节码。 本文档未涉及优化,因为它要求你充分了解匹配引擎的内部结构。
正则表达式语言相对较小且受限制,因此并非所有可能的字符串处理任务都可以使用正则表达式完成。 还有一些任务 可以 用正则表达式完成,但表达式变得非常复杂。 在这些情况下,你最好编写 Python 代码来进行处理;虽然 Python 代码比精心设计的正则表达式慢,但它也可能更容易理解。

正则表达式的语法

正则表达式(或 RE)指定了一组与之匹配的字符串;模块内的函数可以检查某个字符串是否与给定的正则表达式匹配
python中的正则表达式有内置的模块re. 只要导入就能使用。(import re)

re模块的方法

有了准备知识,我们就可以在Python中使用正则表达式了。Python提供re模块,包含所有正则表达式的功能。由于Python的字符串本身也用\转义,所以要特别注意。 因此强烈建议使用Python的r前缀(raw模式),就不用考虑转义的问题了

方法 / 属性 目的
match() 确定正则是否从字符串的开头匹配。
search() 扫描字符串,查找此正则匹配的任何位置。
findall() 找到正则匹配的所有子字符串,并将它们作为列表返回。
finditer() 找到正则匹配的所有子字符串,并将它们返回为一个 iterator。
sub() 用于替换字符串中的匹配项
split() 将字符串拆分成列表

match()方法

  • 判断是否匹配,如果匹配成功,返回一个Match对象,否则返回None。
  • 从头开始匹配
1
2
import re
re.match(r'^\d{3}-\d{3,8}$', '010-12345')
1
<re.Match object; span=(0, 9), match='010-12345'>

查看匹配结果

方法 / 属性 目的
group() 返回正则匹配的字符串
start() 返回匹配的开始位置
end() 返回匹配的结束位置
span() 返回包含匹配 (start, end) 位置的元组
  • group() 返回正则匹配的子字符串。
  • start() 和 end() 返回匹配的起始和结束索引。
  • span() 在单个元组中返回开始和结束索引。
  • 由于 match() 方法只检查正则是否在字符串的开头匹配,所以 start() 将始终为零。

如果正则表达式中定义了组,就可以在Match对象上用group()方法提取出子串来。
注意到group(0)永远是原始字符串,group(1)、group(2)……表示第1、2、……个子串。

但是,模式的 search() 方法会扫描字符串,因此在这种情况下匹配可能不会从零开始。:

exp
1
2
3
4
5
6
result=re.match(r'\d{3}-\d{3,8}', '010-12345678')
result

result.group()
result.start(),result.end()
result.span()
1
2
3
4
<re.Match object; span=(0, 12), match='010-12345678'>
'010-12345678'
(0, 12)
(0, 12)
exp
1
2
3
4
5
6
result=re.match(r'(\d{3})-\d{3,8}', '010-1234567890')
result

result.group(),result.group(0),result.group(1)
result.start(),result.end()
# result.span()
1
2
3
<re.Match object; span=(0, 12), match='010-12345678'>
('010-12345678', '010-12345678', '010')
(0, 12)

serch()方法

  • 在要查找的字符串中从左到右开始查找,找到1个后就返回匹配对象,否则None
exp
1
2
3
4
5
6
result=re.search (r'(\d{3})-(\d{3,8})', '087010-123456789013579-1234678902468')
result

result.group(),result.group(0),result.group(1),result.group(2)
result.start(),result.end()
result.span()
1
2
3
4
<re.Match object; span=(3, 15), match='010-12345678'>
('010-12345678', '010-12345678', '010', '12345678')
(3, 15)
(3, 15)

findall()方法

  • 在查找范围内找出所有符合条件的匹配对象
  • 返回一个列表
exp
1
2
result=re.findall (r'(\d{3})-(\d{3,8})', '087010-123456789013579-1234678902468')
result
1
[('010', '12345678'), ('579', '12346789')]

finditer() 方法

  • 将一个 匹配对象 的序列返回为一个 iterator
exp
1
2
3
4
5
result = re.finditer(r'(\d{3})-(\d{3,8})',
'087010-123456789013579-1234678902468')
result

[x for x in result]
1
<callable_iterator at 0x67c3238>
exp
[<re.Match object; span=(3, 15), match='010-12345678'>,
 <re.Match object; span=(19, 31), match='579-12346789'>]
1
2
3
4
5
6
7

result = re.finditer(r'(\d{3})-(\d{3,8})',
'087010-123456789013579-1234678902468')
result


[x.groups() for x in result]
1
2
<callable_iterator at 0x66ae9b8>
[('010', '12345678'), ('579', '12346789')]

sub()方法

  • 用于替换字符串中的匹配项
exp
1
2
3
4
# 将‘-’ 替换成空格‘***’
result = re.sub(r'-','***',
'087010-123456789013579-1234678902468')
result
1
'087010***123456789013579***1234678902468'
exp
1
2
3
4
# 将大于4的数字 替换成空格‘***’
result = re.sub(r'[5-9]','*',
'087010-123456789013579-1234678902468')
result
1
'0**010-1234*****013***-1234****024**'

split方法

  • 能够按照所能匹配的字串将字符串进行切分,返回切分后的字符串列表
  • re.split(pattern, string, maxsplit=0, flags=0)
  • pattern:匹配的字符串
  • string:需要切分的字符串
  • maxsplit:分隔次数,默认为0(即不限次数)
  • flags:标志位,用于控制正则表达式的匹配方式,比如:是否区分大小写
exp
1
2
3
4
str1 = 'ab cde f  gHi'
re.split(r'\s',str1)

re.split(r'\s+',str1)
1
2
['ab', 'cde', 'f', '', 'gHi']
['ab', 'cde', 'f', 'gHi']
exp
1
2
str1 = 'ab cde f  gHi'
re.split(r'\s+',str1,2)
1
['ab', 'cde', 'f  gHi']

元字符

. ^ $ * + ? { } [ ] \ | ( )

符号 意义
. 半角句号,匹配任意单个字符,除了换行符。
[ ] 字符种类。匹配方括号内的任意字符
[^] 否定的字符种类。匹配除了方括号内的任意字符
* 匹配 >= 0 个重复的 在 * 号之前的字符
+ 匹配 >= 1 个重复的 在 + 号之前的字符
? 匹配 0 ~1 个重复的 在 ? 号之前的字符
{n} 匹配 = n 个 {} 号之前的字符或字符集
{n,} 匹配 >=n 个 {} 号之前的字符或字符集
{n,m} 匹配 >=n ~ <=m 个 {} 号之前的字符或字符集
(abc) 字符集。匹配与 abc 相等的字符串
| 运算符。匹配符号前或后的字符
^ 从首位开始匹配
$ 从末尾开始匹配
\ 转义字符。用于匹配一些保留的字符 如:[] () { } . * + ? ^ $ \ |

组合

(...)

(组合),匹配括号内的任意正则表达式,并标识出组合的开始和结尾。匹配完成后,组合的内容可以被获取,并可以在之后用 \number 转义序列进行再次匹配,之后进行详细说明。要匹配字符 ‘(‘ 或者 ‘)’, 用 ( 或 ), 或者把它们包含在字符集合里: [(], [)].

(?…)

这是个扩展标记法 (一个 ‘?’ 跟随 ‘(‘ 并无含义)。 ‘?’ 后面的第一个字符决定了这个构建采用什么样的语法。这种扩展通常并不创建新的组合; (?P <name>…) 是唯一的例外。 以下是目前支持的扩展。

(?aiLmsux)

( ‘a’, ‘i’, ‘L’, ‘m’, ‘s’, ‘u’, ‘x’ 中的一个或多个) 这个组合匹配一个空字符串;这些字符对正则表达式设置以下标记 re.A (只匹配ASCII字符), re.I (忽略大小写), re.L (语言依赖), re.M (多行模式), re.S (点dot匹配全部字符), re.U (Unicode匹配), and re.X (冗长模式)。 (这些标记在 模块内容 中描述) 如果你想将这些标记包含在正则表达式中,这个方法就很有用,免去了在 re.compile() 中传递 flag 参数。标记应该在表达式字符串首位表示。

(?:…)

正则括号的非捕获版本。 匹配在括号内的任何正则表达式,但该分组所匹配的子字符串 不能 在执行匹配后被获取或是之后在模式中被引用。

(?aiLmsux-imsx:…)

(‘a’, ‘i’, ‘L’, ‘m’, ‘s’, ‘u’, ‘x’ 中的0或者多个, 之后可选跟随 ‘-‘ 在后面跟随 ‘i’ , ‘m’ , ‘s’ , ‘x’ 中的一到多个 .) 这些字符为表达式的其中一部分 设置 或者 去除 相应标记 re.A (只匹配ASCII), re.I (忽略大小写), re.L (语言依赖), re.M (多行), re.S (点匹配所有字符), re.U (Unicode匹配), and re.X (冗长模式)。(标记描述在 模块内容 .)

‘a’, ‘L’ and ‘u’ 作为内联标记是相互排斥的, 所以它们不能结合在一起,或者跟随 ‘-‘ 。 当他们中的某个出现在内联组中,它就覆盖了括号组内的匹配模式。在Unicode样式中, (?a:…) 切换为 只匹配ASCII, (?u:…) 切换为Unicode匹配 (默认). 在byte样式中 (?L:…) 切换为语言依赖模式, (?a:…) 切换为 只匹配ASCII (默认)。这种方式只覆盖组合内匹配,括号外的匹配模式不受影响。

(?P<name>…)

(命名组合)类似正则组合,但是匹配到的子串组在外部是通过定义的 name 来获取的。组合名必须是有效的Python标识符,并且每个组合名只能用一个正则表达式定义,只能定义一次。一个符号组合同样是一个数字组合,就像这个组合没有被命名一样。

命名组合可以在三种上下文中引用。如果样式是 (?P <quote>[‘“]).*?(?P=quote) (也就是说,匹配单引号或者双引号括起来的字符串):

引用组合 “quote” 的上下文 引用方法
在正则式自身内 (?P=quote) (如示)\1
处理匹配对象m m.group('quote')``m.end('quote') (等)
传递到 re.sub() 里的 repl 参数中 \g<quote>``\g<1>``\1

(?P=name)

反向引用一个命名组合;它匹配前面那个叫 name 的命名组中匹配到的串同样的字串。

(?#…)

(?#…)
注释;里面的内容会被忽略。

(?=…)
匹配 … 的内容,但是并不消费样式的内容。这个叫做 lookahead assertion。比如, Isaac (?=Asimov) 匹配 ‘Isaac ‘ 只有在后面是 ‘Asimov’ 的时候。

(?!…)
匹配 … 不符合的情况。这个叫 negative lookahead assertion (前视取反)。比如说, Isaac (?!Asimov) 只有后面 不 是 ‘Asimov’ 的时候才匹配 ‘Isaac ‘ 。

(?<=…)

匹配字符串的当前位置,它的前面匹配 … 的内容到当前位置。这叫 positive lookbehind assertion (正向后视断定)。 (?<=abc)def 会在 ‘abcdef’ 中找到一个匹配,因为后视会往后看3个字符并检查是否包含匹配的样式。包含的匹配样式必须是定长的,意思就是 abc 或 a|b 是允许的,但是 a* 和 a{3,4} 不可以。注意以 positive lookbehind assertions 开始的样式,如 (?<=abc)def ,并不是从 a 开始搜索,而是从 d 往回看的。你可能更加愿意使用 search() 函数,而不是 match() 函数:

(?<!…)

匹配当前位置之前不是 … 的样式。这个叫 negative lookbehind assertion (后视断定取非)。类似正向后视断定,包含的样式匹配必须是定长的。由 negative lookbehind assertion 开始的样式可以从字符串搜索开始的位置进行匹配.

(?(id/name)yes-pattern|no-pattern)

如果给定的 id 或 name 存在,将会尝试匹配 yes-pattern ,否则就尝试匹配 no-pattern,no-pattern 可选,也可以被忽略。
比如,()?(\w+@\w+(?:.\w+)+)(?(1)?(%5Cw+@%5Cw+(?:%5C.%5Cw+)+)(?(1))|$)
是一个email样式匹配,将匹配 ‘user@host.com‘ 或 ‘user@host.com‘ ,但不会匹配 ‘<user@host.com‘ ,也不会匹配 ‘user@host.com>’。

\ 和字母的特殊序列

\number

匹配数字代表的组合。每个括号是一个组合,组合从1开始编号。比如 (.+) \1 匹配 ‘the the’ 或者 ‘55 55’, 但不会匹配 ‘thethe’ (注意组合后面的空格)。这个特殊序列只能用于匹配前面99个组合。如果 number 的第一个数位是0, 或者 number 是三个八进制数,它将不会被看作是一个组合,而是八进制的数字值。在 ‘[‘ 和 ‘]’ 字符集合内,任何数字转义都被看作是字符。

\A

只匹配字符串开始。

\b\B

\b匹配空字符串,但只在单词开始或结尾的位置。一个单词被定义为一个单词字符的序列。注意,通常 \b 定义为 \w 和 \W 字符之间,或者 \w 和字符串开始/结尾的边界, 意思就是 r’\bfoo\b’ 匹配 ‘foo’, ‘foo.’, ‘(foo)’, ‘bar foo baz’ 但不匹配 ‘foobar’ 或者 ‘foo3’。

\B 匹配空字符串,但不能在词的开头或者结尾。意思就是 r’py\B’ 匹配 ‘python’, ‘py3’, ‘py2’, 但不匹配 ‘py’, ‘py.’, 或者 ‘py!’. \B 是 \b 的取非,所以Unicode样式的词语是由Unicode字母,数字或下划线构成的,虽然可以用 ASCII 标志来改变。如果使用了 LOCALE 标志,则词的边界由当前语言区域设置。

\d\D

\d 对于 Unicode (str) 样式:
匹配任何Unicode十进制数(就是在Unicode字符目录[Nd]里的字符)。这包括了 [0-9] ,和很多其他的数字字符。如果设置了 ASCII 标志,就只匹配 [0-9] 。对于8位(bytes)样式:匹配任何十进制数,就是 [0-9]。

\D 匹配任何非十进制数字的字符。就是 \d 取非。 如果设置了 ASCII 标志,就相当于 [^0-9] 。

\s\S

\s 对于 Unicode (str) 样式:匹配任何Unicode空白字符(包括 [ \t\n\r\f\v] ,还有很多其他字符,比如不同语言排版规则约定的不换行空格)。如果 ASCII 被设置,就只匹配 [ \t\n\r\f\v] 。对于8位(bytes)样式:匹配ASCII中的空白字符,就是 [ \t\n\r\f\v] 。

\S 匹配任何非空白字符。就是 \s 取非。如果设置了 ASCII 标志,就相当于 [^ \t\n\r\f\v] 。

\w\W

\w对于 Unicode (str) 样式:匹配Unicode词语的字符,包含了可以构成词语的绝大部分字符,也包括数字和下划线。如果设置了 ASCII 标志,就只匹配 [a-zA-Z0-9_] 。对于8位(bytes)样式:匹配ASCII字符中的数字和字母和下划线,就是 [a-zA-Z0-9_] 。如果设置了 LOCALE 标记,就匹配当前语言区域的数字和字母和下划线。

\W 匹配非单词字符的字符。这与 \w正相反。如果使用了 ASCII 旗标,这就等价于 [^a-zA-Z0-9_]。如果使用了 LOCALE 旗标,则会匹配当前区域中既非字母数字也非下划线的字符。

\Z

只匹配字符串尾。

常用表达式

校验字符

匹配内容 表达式
汉字 ^[\u4e00-\u9fa5]{0,}$
英文和数字 ^[A-Za-z0-9]+$ ``或 ^[A-Za-z0-9]{4,40}$
长度为3-20的所有字符 ^.{3,20}$
由26个英文字母组成的字符串 ^[A-Za-z]+$
由26个大写英文字母组成的字符串 ^[A-Z]+$
由26个小写英文字母组成的字符串 ^[a-z]+$
由数字和26个英文字母组成的字符串 ^[A-Za-z0-9]+$
由数字、26个英文字母或者下划线组成的字符串 ^\w+$ 或 ^\w{3,20}$
中文、英文、数字包括下划线 ^[\u4E00-\u9FA5A-Za-z0-9_]+$
中文、英文、数字但不包括下划线等符号 ^[\u4E00-\u9FA5A-Za-z0-9]+$ ``或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
可以输入含有^%&’,;=?$"等字符 [^%&',;=?$\x22]+ 12
禁止输入含有~的字符 [^~\x22]+
全角符号 [\uFF00-\uFFFF]
半角符号 [\u0000-\u00FF]

校验数字

匹配内容 表达式
数字 ^[0-9]*$
n位的数字 ^\d{n}$
至少n位的数字 ^\d{n,}$
m-n位的数字 ^\d{m,n}$
零和非零开头的数字 ^(0|[1-9][0-9]*)$
非零开头的最多带两位小数的数字 ^([1-9][0-9]*)+(.[0-9]{1,2})?$
带1-2位小数的正数或负数 ^(\-)?\d+(\.\d{1,2})?$
正数、负数、和小数 ^(\-|\+)?\d+(\.\d+)?$
有两位小数的正实数 ^[0-9]+(.[0-9]{2})?$
有1~3位小数的正实数 ^[0-9]+(.[0-9]{1,3})?$
非零的正整数 ^[1-9]\d*$^([1-9][0-9]*){1,3}$^\+?[1-9][0-9]*$
非零的负整数 ^\-[1-9][]0-9"*$^-[1-9]\d*$
非负整数 ^\d+$^[1-9]\d*|0$
非正整数 ^-[1-9]\d*|0$<或 ^((-\d+)|(0+))$
非负浮点数 ^\d+(\.\d+)?$^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
非正浮点数 ^((-\d+(\.\d+)?)|(0+(\.0+)?))$^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
正浮点数 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
负浮点数 ^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
浮点数 ^(-?\d+)(\.\d+)?$^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$

特殊匹配

匹配内容 表达式
Email地址 ^\w+([-+]\w+)*@\w+([-]\w+)*\\w+([-]\w+)*$
域名 [a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/?
InternetURL [a-zA-z]+://[^\s]*^http://([\w-]+\)+[\w-]+(/[\w-/?%&=]*)?$
手机号码 `^(13[0-9]
电话号码 ^(\(\d{3,4}-)|\d{34}-)?\d{7,8}$
国内电话号码(0511-4405222、021-87888822) `\d{3}-\d{8}
身份证号(15位、18位数字) ^\d{15}|\d{18}$
短身份证号码(数字、字母x结尾) `^([0-9]){7,18}(x
帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线) ^[a-zA-Z][a-zA-Z0-9_]{4,15}$
密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线) ^[a-zA-Z]\w{5,17}$
强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间) ^(?=*\d)(?=*[a-z])(?=*[A-Z]){8,10}$
日期格式 ^\d{4}-\d{1,2}-\d{1,2}
一年的12个月(01~09和1~12) `r’^(0?[1-9]
一个月的31天(01~09和1~31) `r’^((0?[1-9])
xml文件 `r’^([a-zA-Z]+-?)+[a-zA-Z0-9]+[x
1到3个数字,后面跟个逗号+3个数字,逗号成为可选,而不是必须 `r’^([0-9]+
中文字符的正则表达式 r'[\u4e00-\u9fa5]'
双字节字符 [^\x00-\xff](可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
空白行的正则表达式 r '\n\s*\r'(可以用来删除空白行)
首尾空白字符的正则表达式 ^\s*|\s*$(^\s*)|(\s*$)(可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
腾讯QQ号(腾讯QQ号从10000开始) [1-9][0-9]{4,}
中国邮政编码 [1-9]\d{5}(?!\d)
提取网页图片 \\<*[img][^\\\\>]*[src]*=*[\\"\\']{0,1}([^\\"\\'\\>]*)
提取网页颜色代码 r’^#([A-Fa-f0-9]{6}
文件扩展名效验 `r’^([a-zA-Z]:|\)\([^\]+\)[^/:?”<>