Python正则表达式操作指南:https://wiki.ubuntu.org.cn/Python正则表达式操作指南
菜鸟教程 之 python 正则表达式:http://www.runoob.com/python/python-reg-expressions.html
python 官网正则文档:https://docs.python.org/zh-cn/3.13/library/re.html
1、正则表达式基础
1.1. 正则表达式 "语法、元字符"
正则表达式是用于处理字符串的强大工具,大部分编程语言都提供有正则处理字符串的功能。正则表达式的语法都是一样的,区别只在于不同的编程语言实现支持的语法数量不同。
下图展示了使用正则表达式进行匹配的流程:
正则表达式的大致匹配过程是:依次拿出表达式和文本中的字符比较,如果每一个字符都能匹配,则匹配成功;一旦有匹配不成功的字符则匹配失败。如果表达式中有量词或边界,这个过程会稍微有一些不同,但也是很好理解的,看下图中的示例以及自己多使用几次就能明白。
下图列出了 Python 支持的正则表达式元字符和语法:
1.2. 数量词的 "贪婪、非贪婪"
正则表达式通常用于在文本中查找匹配的字符串。Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;非贪婪的则相反,总是尝试匹配尽可能少的字符。
例如:正则表达式 "ab*" 如果用于查找 "abbbc",将找到"abbb"。
而如果使用非贪婪的数量词"ab*?",将找到"a"。
示例:abc123def123ghi123
贪婪匹配
- :abc.*?
- :abc.*123
非贪婪匹配:adc.*?123
1.3. 转义字符 \
与大多数编程语言相同,正则表达式里使用"\"作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符"\",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\\\\":前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。Python里的原生字符串很好地解决了这个问题,这个例子中的正则表达式可以使用r"\\"表示。同样,匹配一个数字的"\\d"可以写成r"\d"。有了原生字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。
1.4. 匹配模式
正则表达式提供了一些可用的匹配模式,比如忽略大小写、多行匹配等
- re.I (即 IGNORECASE):忽略大小写(括号内是完整写法,下同)
- re.M (即 MULTILINE):多行模式,改变'^'和'$'的行为(参见上图)
- re.S (即 DOTALL):点任意匹配模式,改变'.'的行为
- re.L (即 LOCALE):使预定字符类 \w \W \b \B \s \S 取决于当前区域设定
- re.U (即 UNICODE):使预定字符类 \w \W \b \B \s \S \d \D 取决于unicode定义的字符属性
- re.X (即 VERBOSE):详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释。
2、Python 的 re 模块
以下是正则表达式格式的简要说明。更详细的信息和演示,参考 正则表达式指南。
.
(点号.) 在默认模式下,匹配除换行符以外的任意字符。 如果指定了旗标 DOTALL,它将匹配包括换行符在内的任意字符。(?s:.)
将匹配任意字符而无视相关旗标。^
(插入符) 匹配字符串的开头, 并且在 MULTILINE 模式下也匹配换行后的首个符号。$
(美元符) 匹配字符串尾或者在字符串尾的换行符的前一个字符,在 MULTILINE 模式下也会匹配换行符之前的文本。foo
匹配 'foo' 和 'foobar',但正则表达式foo$
只匹配 'foo'。 更有趣的是,在'foo1\nfoo2\n'
中搜索foo.$
,通常匹配 'foo2',但在 MULTILINE 模式下可以匹配到 'foo1';在'foo\n'
中搜索$
会找到两个(空的)匹配:一个在换行符之前,一个在字符串的末尾。*
(星号) 对它前面的正则式匹配0到任意次重复, 尽量多的匹配字符串。ab*
会匹配'a'
,'ab'
,或者'a'
后面跟随任意个'b'
。+
(加号) 对它前面的正则式匹配1到任意次重复。ab+
会匹配'a'
后面跟随1个以上到任意个'b'
,它不会匹配'a'
。?
(问号) 对它前面的正则式匹配0到1次重复。ab?
会匹配'a'
或者'ab'
。*?
,+?
,??
是非贪婪匹配。'*'
,'+'
和'?'
数量限定符都是 贪婪的;它们会匹配尽可能多的文本。 有时这种行为并不被需要;如果 RE<.*>
针对'<a> b <c>'
进行匹配,它将匹配整个字符串,而不只是'<a>'
。 在数量限定符之后添加?
将使其以 非贪婪 或 最小 风格来执行匹配;也就是将匹配数量尽可能 少的 字符。 使用 RE<.*?>
将只匹配'<a>'
。*+
,++
,?+
类似于'*'
,'+'
和'?'
数量限定符,添加了'+'
的形式也将匹配尽可能多的次数。 但是,不同于真正的贪婪型数量限定符,这些形式在之后的表达式匹配失败时不允许反向追溯。 这些形式被称为 占有型 数量限定符。 例如,a*a
将匹配'aaaa'
因为a*
将匹配所有的 4 个'a'
,但是,当遇到最后一个'a'
时,表达式将执行反向追溯以便最终a*
最后变为匹配总计 3 个'a'
,而第四个'a'
将由最后一个'a'
来匹配。 然而,当使用a*+a
时如果要匹配'aaaa'
,a*+
将匹配所有的 4 个'a'
,但是在最后一个'a'
无法找到更多字符来匹配时,表达式将无法被反向追溯并将因此匹配失败。x*+
,x++
和x?+
分别等价于(?>x*)
,(?>x+)
和(?>x?)
。{m}
对其之前的正则式指定匹配 m 个重复;少于 m 的话就会导致匹配失败。比如,a{6}
将匹配6个'a'
, 但是不能是5个。{m,n}
对正则式进行 m 到 n 次匹配,在 m 和 n 之间取尽量多。 比如,a{3,5}
将匹配 3 到 5个'a'
。忽略 m 意为指定下界为0,忽略 n 指定上界为无限次。 比如a{4,}b
将匹配'aaaab'
或者1000个'a'
尾随一个'b'
,但不能匹配'aaab'
。逗号不能省略,否则无法辨别修饰符应该忽略哪个边界。{m,n}?
将导致结果 RE 匹配之前 RE 的 m 至 n 次重复,尝试匹配尽可能 少的 重复次数。 这是之前数量限定符的非贪婪版本。 例如,在 6 个字符的字符串'aaaaaa'
上,a{3,5}
将匹配 5 个'a'
字符,而a{3,5}?
将只匹配 3 个字符。{m,n}+
将导致结果 RE 匹配之前 RE 的 m 至 n 次重复,尝试匹配尽可能多的重复而 不会 建立任何反向追溯点。 这是上述数量限定符的占有型版本。 例如,在 6 个字符的字符串'aaaaaa'
上,a{3,5}+aa
将尝试匹配 5 个'a'
字符,然后,要求再有 2 个'a'
,这将需要比可用的更多的字符因而会失败,而a{3,5}aa
的匹配将使a{3,5}
先捕获 5 个,然后通过反向追溯再匹配 4 个'a'
,然后用模式中最后的aa
来匹配最后的 2 个'a'
。x{m,n}+
就等同于(?>x{m,n})
。\
转义特殊字符(允许你匹配'*'
,'?'
, 或者此类其他),或者表示一个特殊序列;特殊序列之后进行讨论。如果你没有使用原始字符串(r'raw'
)来表达样式,要牢记Python也使用反斜杠作为转义序列;如果转义序列不被Python的分析器识别,反斜杠和字符才能出现在字符串中。如果Python可以识别这个序列,那么反斜杠就应该重复两次。这将导致理解障碍,所以高度推荐,就算是最简单的表达式,也要使用原始字符串。- | 示例:
A|B
匹配 A 或者 B。A 和 B 可以是任意正则表达式。任意个正则表达式可以用'|'
连接。它也可以在组合(见下列)内使用。扫描目标字符串时,'|'
分隔开的正则样式从左到右进行匹配。当一个样式完全匹配时,这个分支就被接受。意思就是,一旦 A 匹配成功, B 就不再进行匹配,即便它能产生一个更好的匹配。或者说,'|'
操作符绝不贪婪。 如果要匹配'|'
字符,使用\|
, 或者把它包含在字符集里,比如 [|] -
(...)
(组合),匹配括号内的任意正则表达式,并标识出组合的开始和结尾。匹配完成后,组合的内容可以被获取,并可以在之后用\number
转义序列进行再次匹配,之后进行详细说明。要匹配字符'('
或者')'
, 用\(
或\)
, 或者把它们包含在字符集合里:[(]
,[)]
- \number 匹配数字代表的组合。每个括号是一个组合,组合从1开始编号。比如 (.+) \1 匹配 'the the' 或者 '55 55', 但不会匹配 'thethe' (注意组合后面的空格)。这个特殊序列只能用于匹配前面99个组合。如果 number 的第一个数位是0, 或者 number 是三个八进制数,它将不会被看作是一个组合,而是八进制的数字值。在 '[' 和 ']' 字符集合内,任何数字转义都被看作是字符。
- \A 只匹配字符串开始。
- \b 匹配空字符串,但只在单词开始或结尾的位置。 一个单词被定义为一个单词字符的序列。 注意在通常情况下,\b 被定义为 \w 和 \W 字符之间的边界(反之亦然),或是 \w 和字符串开始或结尾之间的边界。 这意味着 r'\bat\b' 将匹配 'at', 'at.', '(at)' 和 'as at ay' 但不匹配 'attempt' 或 'atlas'。
- \B 匹配空字符串,但仅限于它 不在 单词的开头或结尾的情况。 这意味着 r'at\B' 将匹配 'athens', 'atom', 'attorney',但不匹配 'at', 'at.' 或 'at!'。 \B 与 \b 正相反,这样 Unicode (str) 模式中的单词类字符是 Unicode 字母数字或下划线,但这可以通过使用 ASCII 旗标来改变。 如果使用了 LOCALE 旗标则单词边界将根据当前语言区域来确定。
- \d 匹配任意十进制数。等价于 [0-9]
- \D 匹配不属于十进制数码的任意字符。 这与 \d 正相反。
- \s 匹配空白字符。如果使用了 ASCII 旗标则匹配 [ \t\n\r\f\v]。
- \S 匹配非空白字符。 与 \s 正相反。如果使用了 ASCII 旗标则匹配 [^ \t\n\r\f\v]
- \w 匹配单词类字符;这包括所有 Unicode 字母、数字、以及下划线 (_)。等价于 [a-zA-Z0-9_]
\W 匹配不属于单词类字符的任意字符。 与 \w 正相反。 等价于 [^a-zA-Z0-9_]
\Z 只匹配字符串尾
[]
用于表示一个字符集合。在一个集合中:
- 字符可以单独列出,比如
[amk]
匹配'a'
,'m'
, 或者'k'
。 - 可以表示字符范围,通过用
'-'
将两个字符连起来。比如[a-z]
将匹配任何小写ASCII字符,[0-5][0-9]
将匹配从00
到59
的两位数字,[0-9A-Fa-f]
将匹配任何十六进制数位。 如果-
进行了转义 (比如[a\-z]
)或者它的位置在首位或者末尾(如[-a]
或[a-]
),它就只表示普通字符'-'
。 - 特殊字符在集合中会失去其特殊意义。比如
[(+*)]
只会匹配这几个字面字符之一'('
,'+'
,'*'
, or')'
。 - 字符类如
\w
或者\S
(定义如下) 也在集合内被接受,不过它们可匹配的字符则依赖于所使用的 flags。 - 不在集合范围内的字符可以通过 取反 来进行匹配。如果集合首字符是
'^'
,所有 不 在集合内的字符将会被匹配,比如[^5]
将匹配所有字符,除了'5'
,[^^]
将匹配所有字符,除了'^'
.^
如果不在集合首位,就没有特殊含义。 - 要在集合内匹配一个
']'
字面值,可以在它前面加上反斜杠,或是将它放到集合的开头。 例如,[()[\]{}]
和[]()[{}]
都可以匹配右方括号,以及左方括号,花括号和圆括号。 -
Unicode Technical Standard #18 里的嵌套集合和集合操作支持可能在未来添加。这将会改变语法,所以为了帮助这个改变,一个 FutureWarning 将会在有多义的情况里被
raise
,包含以下几种情况,集合由'['
开始,或者包含下列字符序列'--'
,'&&'
,'~~'
, 和'||'
。为了避免警告,需要将它们用反斜杠转义。
(?…) 这是个扩展标记法 (一个 '?'
跟随 '('
并无含义)。 '?'
后面的第一个字符决定了这个构建采用什么样的语法。这种扩展通常并不创建新的组合; (?P<name>...)
是唯一的例外。 以下是目前支持的扩展。
- (?aiLmsux) (一个或多个来自
'a'
,'i'
,'L'
,'m'
,'s'
,'u'
,'x'
集合的字母。) 分组将与空字符串相匹配;这些字母将为整个正则表达式设置相应的旗标:(该旗标在 模块内容 中有介绍。) 这适用于当你希望将该旗标包括为正则表达式的一部分,而不是向 re.compile() 函数传入 flag 参数的情况。 旗标应当在表达式字符串的开头使用。
re.A (仅限 ASCII 匹配)
re.I (忽略大小写)
re.L (依赖于语言区域)
re.M (多行)
re.S (点号匹配所有字符)
re.U (Unicode 匹配)
re.X (详细) - (?:…) 正则括号的非捕获版本。 匹配在括号内的任何正则表达式,但该分组所匹配的子字符串 不能 在执行匹配后被获取或是之后在模式中被引用。
- (?aiLmsux-imsx:…)(零个或多个来自
'a'
,'i'
,'L'
,'m'
,'s'
,'u'
,'x'
集合的字母,后面可以带'-'
再跟一个或多个来自'i'
,'m'
,'s'
,'x'
集合的字母。) 字母 'a', 'L' 和 'u' 在用作内联旗标时是互斥的,所以它们不能相互组合或者带 '-'。 相反,当它们中的某一个出现于内联的分组时,它将覆盖外层分组中匹配的模式。 在 Unicode 模式中 (?a:...) 将切换至仅限 ASCII 匹配,而 (?u:...) 将切换至 Unicode 匹配(默认)。 在字节串模式中 (?L:...) 将切换为基于语言区域的匹配,而 (?a:...) 将切换为仅限 ASCII 匹配(默认)。 这种覆盖将只在内联分组范围内生效,而在分组之外将恢复为原始的匹配模式。 - (?>...) 尝试匹配
...
就像它是一个单独的正则表达式,如果匹配成功,则继续匹配在它之后的剩余表达式。 如果之后的表达式匹配失败,则栈只能回溯到(?>...)
之前 的点,因为一旦退出,这个被称为 原子化分组 的表达式将会丢弃其自身所有的栈点位。 因此,(?>.*).
将永远不会匹配任何东西因为首先.*
将匹配所有可能的字符,然后,由于没有任何剩余的字符可供匹配,最后的.
将匹配失败。 由于原子化分组中没有保存任何栈点位,并且在它之前也没有任何栈点位,因此整个表达式将匹配失败。 -
(?P<name>…) 与常规的圆括号类似,但分组所匹配到了子字符串可通过符号分组名称 name 来访问。 分组名称必须是有效的 Python 标识符,并且在 bytes 模式中它们只能包含 ASCII 范围内的字节值。 每个分组名称在一个正则表达式中只能定义一次。 一个符号分组同时也是一个编号分组,就像这个分组没有被命名过一样。命名组合可以在三种上下文中引用。如果样式是 (?P<quote>['"]).*?(?P=quote) (也就是说,匹配单引号或者双引号括起来的字符串):
- (?P=name) 反向引用一个命名组合;它匹配前面那个叫 name 的命名组中匹配到的串同样的字串。
- (?#…) 注释;里面的内容会被忽略。
- (?=…) 当 … 匹配时,匹配成功,但不消耗字符串中的任何字符。这个叫做 前视断言 (lookahead assertion)。比如, Isaac (?=Asimov) 将会匹配 'Isaac ' ,仅当其后紧跟 'Asimov' 。
- (?!…) 当 … 不匹配时,匹配成功。这个叫 否定型前视断言 (negative lookahead assertion)。例如, Isaac (?!Asimov) 将会匹配 'Isaac ' ,仅当它后面 不是 'Asimov' 。
- (?<=…) 如果 ... 的匹配内容出现在当前位置的左侧,则匹配。这叫做 肯定型后视断言 (positive lookbehind assertion)。 (?<=abc)def 将会在 'abcdef' 中找到一个匹配,因为后视会回退3个字符并检查内部表达式是否匹配。内部表达式(匹配的内容)必须是固定长度的,意思就是 abc 或 a|b 是允许的,但是 a* 和 a{3,4} 不可以。注意,以肯定型后视断言开头的正则表达式,匹配项一般不会位于搜索字符串的开头。很可能你应该使用 search() 函数,而不是 match() 函数
- (?<!…) 如果 ... 的匹配内容没有出现在当前位置的左侧,则匹配。这个叫做 否定型后视断言 (negative lookbehind assertion)。类似于肯定型后视断言,内部表达式(匹配的内容)必须是固定长度的。以否定型后视断言开头的正则表达式,匹配项可能位于搜索字符串的开头。
- (?(id/name)yes-pattern|no-pattern) 如果给定的 id 或 name 存在,将会尝试匹配 yes-pattern ,否则就尝试匹配 no-pattern,no-pattern 可选,也可以被忽略。比如, (<)?(\w+@\w+(?:\.\w+)+)(?(1)>|$) 是一个email样式匹配,将匹配 '<user@host.com>' 或 'user@host.com' ,但不会匹配 '<user@host.com' ,也不会匹配 'user@host.com>'。
re.函数
re 提供了模块级别的方法,这些方法等价于Pattern实例中相对应的方法,两者可以相互替代。模块级别的方法好处是少写一行 re.compile() 代码,缺点是无法复用编译后的 Pattern对象。escape (string) 方法用于将 string 中的正则表达式元字符如*/+/?等之前加上转义符再返回,在需要大量匹配元字符时有那么一点用。
Python 通过 re 模块提供对正则表达式的支持。有两种使用方式:
- 方式 1:直接先将正则表达式的字符串编译为 Pattern 对象,然后使用 Pattern 对象处理文本并获得匹配结果(一个Match实例),最后使用Match实例获得信息,进行其他的操作。
re.compile(string[,flag]) # 返回 pattern 对象。pattern 可以理解为一个匹配模式。
示例:创建一个 正则表达式对象(Pattern 对象),再通过 正则表达式对象 去匹配。# encoding: UTF-8 import re # 将正则表达式编译成Pattern对象 pattern = re.compile(r'hello') # 使用Pattern匹配文本,获得匹配结果,无法匹配时将返回None match = pattern.match('hello world!') if match: # 使用Match获得分组信息 print match.group() page_source = """this is test, hello world""" result = pattern.finditer() for item in result: name = item.group("name") dao = item.group("dao") print(name)
- 方式 2:直接使用 re 相关函数。格式:re.findall( pattern, 要匹配的字符串) 。
提示:findall 可以换成 re 支持的任何函数。以下为 re 支持的部分函数
re.match(pattern, string[, flags])
re.search(pattern, string[, flags])
re.split(pattern, string[, maxsplit])
re.findall(pattern, string[, flags])
re.finditer(pattern, string[, flags])
re.sub(pattern, repl, string[, count])
re.subn(pattern, repl, string[, count])
示例:直接使用 re 相关函数。import re line = "Cats are smarter than dogs" matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I) if matchObj: print "matchObj.group() : ", matchObj.group() print "matchObj.group(1) : ", matchObj.group(1) print "matchObj.group(2) : ", matchObj.group(2) else: print "No match!!" test_string = """ <div> <div> <span class="title">黑客帝国</span> </div> </div> """ result_1 = re.finditer(r'<div>.*?<span class="title">(?P<bie_name>.*?)</span>', test_string, re.S) print(result_1) for item in result_1: print(item.group("bie_name")) # re.S 表示匹配任何字符,包括换行 result_2 = re.findall(r'<div>.*?<span class="title">(?P<pipei_name>.*?)</span>', test_string, re.S) print(result_2) result_3 = re.findall(r'<div>.*?<span class="title">(?P<bie_name>.*?)</span>', test_string) print(result_3) result_4 = re.findall(r'<div>[\S\s]*?<span class="title">(.*?)</span>', test_string) print(result_4)
re.match(pattern, string[, flags])
Match对象是一次匹配的结果,包含了很多关于此次匹配的信息,可以使用Match提供的可读属性或方法来获取这些信息。
属性:
- string: 匹配时使用的文本。
- re: 匹配时使用的Pattern对象。
- pos: 文本中正则表达式开始搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。
- endpos: 文本中正则表达式结束搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。
- lastindex: 最后一个被捕获的分组在文本中的索引。如果没有被捕获的分组,将为None。
- lastgroup: 最后一个被捕获的分组的别名。如果这个分组没有别名或者没有被捕获的分组,将为None。
方法:
- group([group1, …]):
获得一个或多个分组截获的字符串;指定多个参数时将以元组形式返回。group1可以使用编号也可以使用别名;编号0代表整个匹配的子串;不填写参数时,返回group(0);没有截获字符串的组返回None;截获了多次的组返回最后一次截获的子串。 - groups([default]):
以元组形式返回全部分组截获的字符串。相当于调用group(1,2,…last)。default表示没有截获字符串的组以这个值替代,默认为None。 - groupdict([default]):
返回以有别名的组的别名为键、以该组截获的子串为值的字典,没有别名的组不包含在内。default含义同上。 - start([group]):
返回指定的组截获的子串在string中的起始索引(子串第一个字符的索引)。group默认值为0。 - end([group]):
返回指定的组截获的子串在string中的结束索引(子串最后一个字符的索引+1)。group默认值为0。 - span([group]):
返回(start(group), end(group))。 - expand(template):
将匹配到的分组代入template中然后返回。template中可以使用\id或\g<id>、\g<name>引用分组,但不能使用编号0。\id与\g<id>是等价的;但\10将被认为是第10个分组,如果你想表达\1之后是字符'0',只能使用\g<1>0。
import re
m = re.match(r'(\w+) (\w+)(?P<sign>.*)', 'hello world!')
print "m.string:", m.string
print "m.re:", m.re
print "m.pos:", m.pos
print "m.endpos:", m.endpos
print "m.lastindex:", m.lastindex
print "m.lastgroup:", m.lastgroup
print "m.group(1,2):", m.group(1, 2)
print "m.groups():", m.groups()
print "m.groupdict():", m.groupdict()
print "m.start(2):", m.start(2)
print "m.end(2):", m.end(2)
print "m.span(2):", m.span(2)
print r"m.expand(r'\2 \1\3'):", m.expand(r'\2 \1\3')
### output ###
# m.string: hello world!
# m.re: <_sre.SRE_Pattern object at 0x016E1A38>
# m.pos: 0
# m.endpos: 12
# m.lastindex: 3
# m.lastgroup: sign
# m.group(1,2): ('hello', 'world')
# m.groups(): ('hello', 'world', '!')
# m.groupdict(): {'sign': '!'}
# m.start(2): 6
# m.end(2): 11
# m.span(2): (6, 11)
# m.expand(r'\2 \1\3'): world hello!
re.search(pattern, string[, flags])
re.match 与 re.search 的区别
- re.match 只匹配 字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;即 re.match 自带 ^
- re.search 匹配 整个字符串,直到找到一个匹配的
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import re
line = "Cats are smarter than dogs";
matchObj = re.match(r'dogs', line, re.M | re.I)
if matchObj:
print "match --> matchObj.group() : ", matchObj.group()
else:
print "No match!!"
matchObj = re.search(r'dogs', line, re.M | re.I)
if matchObj:
print "search --> matchObj.group() : ", matchObj.group()
else:
print "No match!!"
实例方法 [ | re模块方法]:
- match(string[, pos[, endpos]]) | re.match(pattern, string[, flags]):
这个方法将从string的pos下标处起尝试匹配pattern;如果pattern结束时仍可匹配,则返回一个Match对象;如果匹配过程中pattern无法匹配,或者匹配未结束就已到达endpos,则返回None。
pos和endpos的默认值分别为0和len(string);re.match()无法指定这两个参数,参数flags用于编译pattern时指定匹配模式。
注意:这个方法并不是完全匹配。当pattern结束时若string还有剩余字符,仍然视为成功。想要完全匹配,可以在表达式末尾加上边界匹配符'$'。
示例参见2.1小节。 - search(string[, pos[, endpos]]) | re.search(pattern, string[, flags]):
这个方法用于查找字符串中可以匹配成功的子串。从string的pos下标处起尝试匹配pattern,如果pattern结束时仍可匹配,则返回一个Match对象;若无法匹配,则将pos加1后重新尝试匹配;直到pos=endpos时仍无法匹配则返回None。
pos和endpos的默认值分别为0和len(string));re.search()无法指定这两个参数,参数flags用于编译pattern时指定匹配模式。
# encoding: UTF-8
import re
# 将正则表达式编译成Pattern对象
pattern = re.compile(r'world')
# 使用search()查找匹配的子串,不存在能匹配的子串时将返回None
# 这个例子中使用match()无法成功匹配
match = pattern.search('hello world!')
if match:
# 使用Match获得分组信息
print match.group()
### 输出 ###
# world
re.split(pattern, string[, maxsplit]):
按照能够匹配的子串将string分割后返回列表。maxsplit用于指定最大分割次数,不指定将全部分割。
import re
p = re.compile(r'\d+')
print p.split('one1two2three3four4')
### output ###
# ['one', 'two', 'three', 'four', '']
re.findall(pattern, string[, flags]):
搜索string,以列表形式返回全部能匹配的子串。
import re
p = re.compile(r'\d+')
print p.findall('one1two2three3four4')
### output ###
# ['1', '2', '3', '4']
re.finditer(pattern, string[, flags]):
搜索 string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器。
import re
p = re.compile(r'\d+')
for m in p.finditer('one1two2three3four4'):
print m.group(),
### output ###
# 1 2 3 4
re.sub(pattern, repl, string[, count]):
使用 repl 替换 string 中每一个匹配的子串后返回替换后的字符串。
- 当 repl 是一个字符串时,可以使用 \id 或 \g、\g 引用分组,但不能使用编号0。
- 当 repl 是一个方法时,这个方法应当只接受一个参数(Match对象),并返回一个字符串用于替换( 返回的字符串中不能再引用分组 )。
- count 用于指定最多替换次数,不指定时全部替换。
import re
p = re.compile(r'(\w+) (\w+)')
s = 'i say, hello world!'
print p.sub(r'\2 \1', s)
def func(m):
return m.group(1).title() + ' ' + m.group(2).title()
print p.sub(func, s)
### output ###
# say i, world hello!
# I Say, Hello World!
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import re
phone = "2004-959-559 # This is Phone Number"
# Delete Python-style comments
num = re.sub(r'#.*$', "", phone)
print "Phone Num : ", num
# Remove anything other than digits
num = re.sub(r'\D', "", phone)
print "Phone Num : ", num
# 执行结果如下:
# Phone Num : 2004-959-559
# Phone Num : 2004959559
re.subn(pattern, repl, string[, count]):
返回 ( sub(repl, string[, count]), 替换次数 )。
import re
p = re.compile(r'(\w+) (\w+)')
s = 'i say, hello world!'
print p.subn(r'\2 \1', s)
def func(m):
return m.group(1).title() + ' ' + m.group(2).title()
print p.subn(func, s)
### output ###
# ('say i, world hello!', 2)
# ('I Say, Hello World!', 2)
正则表达式对象 (Pattern 对象)
正则表达式对象(Pattern) 不能直接实例化,必须使用 re.compile() 返回。re.compile 方法是 Pattern 类的工厂方法,用于将 字符串形式的正则表达式 编译为 Pattern对象。Pattern 对象其实就是一个已经编译好的正则表达式,可以通过 Pattern 提供的方法对文本进行匹配查找。
Pattern 提供了几个可读属性用于获取表达式的相关信息:
- pattern: 编译时用的表达式字符串。
- flags:编译时用的匹配模式。数字形式。取值可以使用按位或运算符'|'表示同时生效,比如re.I | re.M。另外,你也可以在regex字符串中指定模式,比如re.compile('pattern', re.I | re.M)与re.compile('(?im)pattern')是等价的。
可选值有:
re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)
re.M(MULTILINE): 多行模式,改变'^'和'$'的行为(参见上图)
re.S(DOTALL): 点任意匹配模式,改变'.'的行为
re.L(LOCALE): 使预定字符类 \w \W \b \B \s \S 取决于当前区域设定
re.U(UNICODE): 使预定字符类 \w \W \b \B \s \S \d \D 取决于unicode定义的字符属性
re.X(VERBOSE): 详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释。以下两个正则表达式是等价的: - groups: 表达式中分组的数量。
- groupindex: 以表达式中有别名的组的别名为键、以该组对应的编号为值的字典,没有别名的组不包含在内。
import re
p = re.compile(r'(\w+) (\w+)(?P<sign>.*)', re.DOTALL)
print "p.pattern:", p.pattern
print "p.flags:", p.flags
print "p.groups:", p.groups
print "p.groupindex:", p.groupindex
### output ###
# p.pattern: (\w+) (\w+)(?P<sign>.*)
# p.flags: 16
# p.groups: 3
# p.groupindex: {'sign': 3}