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好理解。

时间: 2024-12-30 21:18:42

Python——正則表達式(2)的相关文章

Python正則表達式小结(1)

学习一段python正則表達式了, 对match.search.findall.finditer等函数作一小结  以下以一段网页为例,用python正則表達式作一个范例: strHtml = '''<div> <a href="/user/student/" class="user-t"><img src="/uploads/avatar/2015/06/082e408c-14fc-11e5-a98d-00163e02100b

python进阶十_正則表達式(一)

近期状态一直不太好,至于原因.怎么说呢,不好说,总之就是纠结中覆盖着纠结.心思全然不在点上.希望能够借助Python的学习以及博客的撰写来调整回来,有的时候回头想一想.假设真的是我自己的问题呢,曾经我常常跟别人说,千万不要怀疑自己.由于非常清楚一旦连自己都变的不可信.那这个世界就太疯狂了,当一遍一遍的问我,如今连我自己都快怀疑自己了,我一遍一遍的说服别人,想不到如今居然须要自己去说服自己,何其的悲哀~ 一.正則表達式基础 1.基本概念 正則表達式是计算机科学的一个概念.正則表達式使用单个字符串来

Python - 连续替换(replace)的正則表達式(re)

字符串连续替换, 能够连续使用replace, 也能够使用正則表達式. 正則表達式, 通过字典的样式, key为待替换, value为替换成, 进行一次替换就可以. 代码 # -*- coding: utf-8 -*- import re my_str = "(condition1) and --condition2--" print my_str.replace("condition1", "").replace("condition

javascript中的正則表達式

对文本数据进行操作是JavaScript中常见的任务.正則表達式通过同意程序猿指定字符串匹配的模式来简化诸如验证表单中输入是否具有正确格式之类的任务. 1.正則表達式标记: 字符 含义 举例 i 大写和小写不敏感 对于模式/http/i  "http" 和"HttP" 一样能够匹配 g 全局匹配.找出所有匹配字符串,而不不过找到第一个就返回. 经常使用于替换 m 多行匹配 2.正則表達式位置指示符:规定模式在它所匹配的字符串里的位置. 字符 含义 举例 ^ 开头 对

经验之谈—正則表達式实现图文混排

在项目中,我们常常须要发表情,以及常常须要将表情字符转换成表情.由于表情是一个图片.所以我们发给server的时候,实际上是发一段特殊的文字给server,然后转换成表情.以免浪费用户过多的流量. 那接下来.我们就来介绍一下,怎样使用正則表達式实现图文混排呢? 为了以后的代码的管理方便,我们抽取出两个类: NSString+Regular.h中.我们暴露两个方法出来: /** * 返回正則表達式匹配的第一个结果 * * @param pattern 正則表達式 * * @return 匹配的第一

JAVA学习第六十五课 — 正則表達式

正則表達式:主要应用于操作字符串.通过一些特定的符号来体现 举例: QQ号的校验 6~9位.0不得开头.必须是数字 String类中有matches方法 matches(String regex) 告知此字符串是否匹配给定的正則表達式. regex,就是给定的正則表達式 public static void checkQQ() { //第一位是数字1-9,第二位以后是0-9,除去第一位数剩下数字位数范围是5到8位 String regex = "[1-9][0-9]{5,8}";//正

HDU-1039-Easier Done Than Said?(Java &amp;amp;&amp;amp; 没用正則表達式是我的遗憾.....)

Easier Done Than Said? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 9845    Accepted Submission(s): 4784 Problem Description Password security is a tricky thing. Users prefer simple password

正則表達式

一.概述 正則表達式是一种能够用于模式匹配和替换的强有力的工具.其作用例如以下: (1)測试字符串的某个模式.比如,能够对一个输入字符串进行測试,看在该字符串是否存在一个电话号码模式或一个信用卡号码模式.这称为数据有效性验证. (2)替换文本.能够在文档中使用一个正則表達式来标识特定文字,然后能够所有将其删除,或者替换为别的文字: (3)依据模式匹配从字符串中提取一个子字符串. 能够用来在文本或输入字段中查找特定文字. 二.匹配字符 字符 解释说明 \ 将下一字符标记为特殊字符.文本.反向引用或

js正則表達式语法

1. 正則表達式规则 1.1 普通字符 字母.数字.汉字.下划线.以及后边章节中没有特殊定义的标点符号,都是"普通字符".表达式中的普通字符,在匹配一个字符串的时候,匹配与之同样的一个字符. 举例1:表达式 "c",在匹配字符串 "abcde" 时,匹配结果是:成功:匹配到的内容是:"c":匹配到的位置是:開始于2,结束于3.(注:下标从0開始还是从1開始,因当前编程语言的不同而可能不同) 举例2:表达式 "bcd&