Python——正則表達式(2)
本文译自官方文档:Regular Expression HOWTO
參考文章:Python——正則表達式(1)
全文下载 :Python正則表達式基础
======================================================================================
3.使用正則表達式
如今。我们已经学习了一些简单的正則表達式,但我们应该怎么在Python中使用它们呢?re模块提供了一个连接正則表達式引擎的接口,同意你将RE编译成对象并利用它们进行匹配。
------------------------------------------------------------------------------------------------------------------------------------------------------
3.1.编译正則表達式
正則表達式被编译成模式对象,该对象拥有非常多方法来进行各种各样的操作,比方依照模式匹配查找或者运行字符串的替换。
>>> import re
>>> p = re.compile('ab*')
>>> p
re.compile('ab*')
re.compile()方法也能够接受一个可选flags參数,用于指定各种特殊功能和语法变更,我们将会在之后一一学习。如今我们看一个简单的样例:
>>> p = re.compile('ab*',re.IGNORECASE)
正則表達式作为一个字符串參数传递给re.compile()方法。因为正則表達式并非Python的核心部分,也没有特殊的语法去表示它们。所以仅仅能被作为字符串处理(有很多应用并不须要RE,所以没有必要把RE纳入Python的核心部分)。相反,正則表達式re模块仅作为C的扩展模块嵌入的Python中,就像socket或者zlib模块。
把正則表達式作为字符串也让Python更加简洁,可是也有一个缺点,下边我们就来谈一谈。
------------------------------------------------------------------------------------------------------------------------------------------------------
3.2.麻烦的反斜杠
就像上文描写叙述的。正則表達式使用反斜杠 \ 来使一些字符拥有特殊的意义(比方\s)或者去掉特殊字符的特殊意义(比方\*就是表示星号而没有特殊的意义)。这会与Python字符串中实现同样功能的字符发生冲突。
假如我们要写一个RE来匹配LaTeX文件里的一个字符串“\section”,首先你要先在程序代码中写出将要匹配的字符串。
接着。你须要在反斜杠以及其它元字符前面加上反斜杠以去掉它们的特殊含义。所以得到结果“\\section”,这个字符串将传递给re.compile()函数。然而,要知道Python字符串中的反斜杠也有特殊意义,所以要再次在两个反斜杠前面加上反斜杠。得到字符串“\\\\section”。
匹配字符串 |
匹配步骤 |
\section | 将要匹配的字符串 |
\\section | 正則表達式中用‘\\’表示‘\’ |
“\\\\section” | Python字符串中也用‘\\’表示‘\’ |
总之。要匹配一个反斜杠字符‘\’,你须要写四个反斜杠‘\\\\’作为一个正則表達式字符串,由于正則表達式必须为双斜杠 \\ ,而每一个反斜杠在Python字符串中也要用双斜杠‘\\’表示。
这就造成了我们须要反复非常多次反斜杠,也让最后的正則表達式字符串难于理解。
解决方法是使用Python中的原始字符串。所谓原始字符串。即在字符串最前面加上字母r。这样字符串中的反斜杠都会被去掉特殊语义,看做普通字符。比方,字符串 r”\n” 是包括‘\’和‘n’两个字符的字符串。而字符串 “\n” 是仅仅有一个换行符的字符串。正則表達式通常使用Python中的原始字符串来表示。
正則表達式字符串 |
原始字符串 |
“ab*” | r”ab*” |
“\\\\section” | r”\\section” |
“\\w+\\s+\\1” | r”\w+\s+\1” |
------------------------------------------------------------------------------------------------------------------------------------------------------
3.3.运行匹配
将正則表達式编译之后会得到一个模式对象,那么你会用它做什么呢?模式对象包括很多方法和属性,我们在这里仅仅介绍最经常使用的几个。你能够通过查看re模块的文档来查看完整的列表。
方法/属性 |
功能 |
match() | 推断一个正則表達式是否从開始处匹配一个字符串 |
search() | 扫描一个字符串,找到正則表達式匹配的第一个位置 |
findall() | 扫描一个字符串,找到匹配正則表達式的全部子字符串,并将它们以列表的形式返回 |
finditer() | 扫描一个字符串,找到匹配正則表達式的全部子字符串,并将它们以迭代器的形式返回 |
假设没有找到匹配的字符串,match()和search()方法会返回None。
假设匹配成功,则会返回一个匹配对象,包括匹配的信息:起始位置和匹配的子字符串等等。
你能够在交互模式下使用re模块来学习这些内容。假设你能够使用tkinter。你能够看一下Tools/demo/redemo.py这个程序,这是随着Python公布的一个演示样例程序。它能够让你输入正則表達式和字符串,并输出两者是否匹配。当你測试一个复杂的正則表達式的时候。redemo.py是非常实用的。Phil Schwartz’s Kodos也是一个开发和測试正則表達式的一个非常实用的交互式工具。
我们使用标准Python解释器来解释这些样例。
首先,打开Python解释器,导入re模块。然后编译一个RE:
>>> import re
>>> p = re.compile('[a-z]+')
>>> p
re.compile('[a-z]+')
如今你能够利用正則表達式 [a-z]+ 来匹配各种字符串。可是一个空的字符串并不能被匹配,由于加号 + 表示反复1次以上,在这样的情况下,match()方法将会返回None。
另外,这个结果在解释器中不会输出。只是你能够明白地调用print()方法来输出这个结果。
>>> p.match('')
>>> print(p.match(''))
None
接着,让我们尝试一个它能够匹配的字符串。比方字符串“tempo”。
这样的情况下。match()方法将会返回一个匹配对象(match object),为了之后使用这个对象,你应该把这个结果保存在一个变量中。
>>> m = p.match('tempo')
>>> m
<_sre.SRE_Match object; span=(0, 5), match='tempo'>
如今你能够利用匹配对象查询匹配字符串的信息。
匹配对象实例也有一些方法和属性。这里列出最重要的几个:
方法/属性 | 功能 |
group() | 返回匹配的字符串 |
start() | 返回字符串匹配的開始位置 |
end() | 返回字符串匹配的结束位置 |
span() | 返回一个元祖表示匹配位置。(開始,结束) |
尝试下面这些样例。你能够非常快理解这些方法:
>>> m.group()
'tempo'
>>> m.start(),m.end()
(0, 5)
>>> m.span()
(0, 5)
group()方法返回由RE.start()和RE.end()位置确定的子字符串。span()方法用一个元祖返回子字符串的開始位置和结束位置。但要注意的是。match()方法是推断正則表達式是否从開始处匹配字符串,所以start()方法总是返回0。
然而,search()方法就不一样了,它扫描整个字符串。匹配的子字符串的開始位置不一定是0。
>>> print(p.match(':::message'))
None
>>> m = p.search(':::message')
>>> print(m)
<_sre.SRE_Match object; span=(3, 10), match='message'>
>>> m.group()
'message'
>>> m.span()
(3, 10)
在实际的程序中,最经常使用的写法是将匹配对象存储在一个变量中,然后检查它是否为None。
就像下边这样:
p = re.compile(…)
m = p.match(‘string goes here’)
if m:
print(‘Match found: ’ , m.group())
else:
print(‘No match’)
有两个方法能够返回全部匹配的子字符串。findall()方法返回全部匹配字符串的列表:
>>> p = re.compile('\d+')
>>> p.findall('12 drummers drumming, 11 pipers piping, 10 lords a-leaping')
['12', '11', '10']
findall()方法须要在它返回结果之前创建出整个列表。
可是finditer()方法将匹配对象作为迭代器返回(译者注:迭代器的方式更节省内存,效率更高)。
>>> iterator = p.finditer('12 drummers drumming, 11 pipers piping, 10 lords a-leaping')
>>> iterator
<callable_iterator object at 0x036A2110>
>>> for match in iterator:
print(match.span()) (0, 2)
(22, 24)
(40, 42)
------------------------------------------------------------------------------------------------------------------------------------------------------
3.4.模块级别的函数
你并不须要去创建一个匹配对象来调用它的方法,re模块中也提供一些全局函数比方match()、search()、findadd()、sub()等等。这些函数的第一个參数是正則表達式字符串,其它參数跟模式对象同名的方法採用一样的參数,返回值也一样。都是返回None或者匹配对象。
>>> print(re.match(r'From\s+','Fromage amk'))
None
>>> print(re.match(r'From\S+','Fromage amk'))
<_sre.SRE_Match object; span=(0, 7), match='Fromage'>
>>> print(re.match(r'From\S+','Fromage amk').group())
Fromage
>>> re.match(r'From\s+','From amk Thu May 14 19:12:10 1998')
<_sre.SRE_Match object; span=(0, 5), match='From '>
事实上,这些函数仅仅是简单地为你创建了一个模式对象,而且能够调用其相关函数。另外。它将编译好的模式对象存放在缓存中,所以假设之后你使用了同样的正則表達式,就不用了再次创建模式了。能够实现高速调用。
那么你应该使用这些模块级别的函数呢?还是应该先编译得到自己模式对象再调用它的方法呢?假设你要在一个循环中使用正則表達式。提前编译它能够节省函数的调用。
但在循环外部,因为内部缓冲机制。两者的效率不差上下。
------------------------------------------------------------------------------------------------------------------------------------------------------
3.5.编译标志
编译标志能够让你在一些方面改变正則表達式的工作方法。编译标志在re模块中有两个可用名称:全称和简写。比方IGNORECASE的简写是字母I(假设熟悉Perl语言的模式编写,你会知道Perl语言的简写和这个一样,比方re.VERBOSE和简写是re.X)。
多个编译标志能够通过逻辑或连接起来。比方re.I | re.M 设置了I和M两个标志。
下表列出了一些可用的编译标志:
编译标志 |
含义 |
ASCII。A | 使得转义符号如\w,\b,\s和\d仅仅匹配ASCII字符 |
DOTALL,S | 使得点号 . 能够匹配不论什么符号,包含换行符 |
IGNORECASE。I | 匹配不区分大写和小写 |
LOCALE,L | 支持当前的语言(区域)设置 |
MULTILINE,M | 多行匹配,会影响^和$ |
VERBOSE。X(for ‘extended’) | 启用具体的正則表達式 |
I
IGNORECASE
匹配不区分大写和小写;使得字符类和文本字符串在匹配字符的时候不区分大写和小写。比如,[A-Z]也会匹配小写字母。Spam会匹配Spam、spam和spAM。假设你不设置LOCALE标志,则不会考虑语言(区域)设置方法的问题。
L
LOCALE
使得\w、\W、\b和\B取决于当前的语言环境,而不是Unicode数据库。
区域设置是C语言库的一个功能,主要为了在编敲代码的时候考虑语言的差异性。比方,假设你正在处理一个法文文本。你想要写 \w+ 来匹配单词。可是 \w 仅仅匹配出如今字符类[a-zA-Z]中的单词,它不会匹配 'é' 或者 'ç’ ,假设你的系统被设置为法语语言环境,那么C语言函数将会觉得 'é' 也是一个字母。当编译正則表達式的时候设置了LOCALE标志。\w 就能够识别法文了。可是它的速度相对要慢一点。
M
MULTILINE
(^和$我们还没有提到。它们将在后面解说)
通常的,^仅仅匹配字符串的开头,而$仅仅匹配字符串的结尾,当这个标志设置的时候,元字符^将会匹配字符串中每一行的的行首,而类似的,元字符$将会匹配每一行的行尾。
S
DOTALL
使得点号‘.’匹配全部的字符。包含换行符。
假设不设置这个标志,点号‘.’将匹配除了换行符之外的全部字符。
A
ASCII
使得\w、\w、\b、\B和\S值匹配ASCII字符,而不是Unicode字符。这个标志仅对Unicode模式有意义,并忽略字节模式。
X
VERBOSE
这个标志能够让你组织正則表達式更具灵活性。从而写的正則表達式更具有可读性。假设设置了这个标志,正則表達式中的空格将会被忽略,当然这里不包含字符类中的空格。也不包含被反斜杠转义的空格,这会让你更清晰地去组织正則表達式。
另外。这个标志也同意在正則表達式式中使用凝视,井号 # 以及之后的字符将会被正則表達式忽略,除非井号 # 在字符类中或者经过了反斜杠转义。
以下看一个使用re.VERBOSE的样例:
>>> charref = re.compile(r'''
&[#] #開始数字引用
(
0[0-7]+ #八进制格式
|[0-9]+ #十进制格式
|x[0-9a-fA-F]+ #十六进制格式
)
; #结尾分号
''',re.VERBOSE)
假设不用VERBOSE设置。这个正則表達式将会是以下这个格式:
>>> charref = re.compile('&[#](0[0-7]+'
'|[0-9]+'
'|x[0-9a-fA-F]+);')
在上述的样例中。我们使用了Python自己主动串联字符串的功能,从而将正則表達式分成了几个更小的部分。可是它依然没有使用re.VERBOSE版本号的RE好理解。
Python——正則表達式(2)的更多相关文章
- Python正則表達式小结(1)
学习一段python正則表達式了, 对match.search.findall.finditer等函数作一小结 以下以一段网页为例,用python正則表達式作一个范例: strHtml = '''& ...
- Python正則表達式
Python正則表達式 正則表達式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配. Python 自1.5版本号起添加了re 模块,它提供 Perl 风格的正則表達式模式. r ...
- Python正則表達式:怎样使用正則表達式
正則表達式(简称RE)本质上能够看作一个小的.高度专业化的编程语言,在Python中能够通过re模块使用它.使用正則表達式,你须要为想要匹配的字符串集合指定一套规则,字符串集合能够包括英文句子.e-m ...
- python 正則表達式推断邮箱格式是否正确
import re def validateEmail(email): if len(email) > 7: if re.match("^.+\\@(\\[?) ...
- python 学习笔记 10 -- 正則表達式
零.引言 在<Dive into Python>(深入python)中,第七章介绍正則表達式,开篇非常好的引出了正則表達式,以下借用一下:我们都知道python中字符串也有比較简单的方法, ...
- python使用正則表達式
python中使用正則表達式 1. 匹配字符 正則表達式中的元字符有 . ^ $ * + ? { } [ ] \ | ( ) 匹配字符用的模式有 \d 匹配随意数字 \D 匹配随意非 ...
- python进阶十_正則表達式(一)
近期状态一直不太好,至于原因,怎么说呢,不好说,总之就是纠结中覆盖着纠结,心思全然不在点上,希望能够借助Python的学习以及博客的撰写来调整回来,有的时候回头想一想,假设真的是我自己的问题呢,曾经我 ...
- python re 正則表達式
夜深了.敲击键盘.用CSDN整理下python re 正則表達式是含有文本和特别字符的字符串,这些文本和特别字符描写叙述的模式能够识别各种字符串. 一下我们从实例结合理论来学习理解吧... 经常使 ...
- 正則表達式re中的贪心算法和非贪心算法 在python中的应用
之前写了一篇有关正則表達式的文章.主要是介绍了正則表達式中通配符 转义字符 字符集 选择符和子模式 可选项和反复子模式 字符串的開始和结尾 ,有兴趣的能够查看博客内容. 此文章主要内容将要介绍re中的 ...
随机推荐
- shell-code-5-函数
# 函数必须在使用前定义 # 如果不写return,将以最后一条命令运行结果,作为返回值. return后跟数值n(0-255) myFistFunc(){ read a read b return ...
- LeetCode(118) Pascal's Triangle
题目 Given numRows, generate the first numRows of Pascal's triangle. For example, given numRows = 5, R ...
- LeetCode101--对称二叉树
''' 给定一个二叉树,检查它是否是镜像对称的. ''' class TreeNode: def __init__(self, x): self.val = x self.left = None se ...
- idea导入jdk源码查看(xjl456852原创)
idea添加了jdk环境后,却无法查看jdk源码,只能通过idea自带的反编译查看,看起来有些不爽. 下面来说一下如何设置,导入jdk源码,查看时通过源码查看jdk. 1.点击菜单 File -> ...
- 1,python初识
什么是变量? 变量:将程序的中间结果暂时存储起来,以便后续程序调用. 什么是字符串类型? python中被引号引起来的数据就是字符串.字符串类型,也简称str类型. 在python中 int是什么? ...
- 【03】图解原型和原型链by魔芋
[03]图解原型和原型链 一图胜前言 请先结合图解原型和原型链这张图. 可以分为4种情况. 情况1: Object有: constructor:是Function. __pro ...
- EasyUI 获取行ID,符合条件的添加样式
function GetTableTrID() { var p = $('#PreFixgrid').prev().find('div table:eq(1)'); var ID = $(p).fin ...
- shell文件包含
像其他语言一样,Shell 也可以包含外部脚本,将外部脚本的内容合并到当前脚本. Shell 中包含脚本可以使用: . filename 或 source filename 两种方式的效果相同,简单起 ...
- linux删除N天前的文件
列出一天之前的文件的属性用下面的命令:find . ! -mtime -1 -print |xargs ls -lfind . -mtime +1 要删除文件的话用下面的命令:find . ! -mt ...
- BZOJ 1419 Red is good ——期望DP
定义f[i][j]表示还剩i张红牌,j张黑牌的时候能取得的期望最大值 显然有$f[i][j]=max(0,\frac {i}{i+j}(f[i-1][j]+1)+ \frac {j}{i+j}(f[i ...