【Python】Python 模式匹配与正则表达式

这篇具有很好参考价值的文章主要介绍了【Python】Python 模式匹配与正则表达式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Python 模式匹配与正则表达式

1. 模式匹配与正则表达式

你可能熟悉文本查找,即按下Ctrl-F,输入你要查找的词。 “正则表达式”更进一步,它们让你指定要查找的“模式”。 你也许不知道一家公司的准确电话号码,但如果你住在美国或加拿大, 你就知道它有3位数字,然后是一个短横线,然后是4位数字(有时候以3位区号开始)。 因此作为一个人,你看到一个电话号码就知道: 415-555-1234 是电话号码,但 4,155,551,234 不是。

正则表达式很有用,但如果不是程序员,很少会有人了解它, 尽管大多数现代文本编辑器和文字处理器(诸如微软的Word或OpenOffice/LibreOffcie), 都有查找和查找替换功能,可以根据正则表达式查找。 正则表达式可以节约大量时间,不仅适用于软件用户,也适用于程序员。 实际上,技术作家Cory Doctorow声称,甚至应该在教授编程之前,先教授正则表达式:

“知道[正则表达式]可能意味着用3步解决一个问题, 而不是用3000步。如果你是一个技术怪侠, 别忘了你用几次击键就能解决的问题, 其他人需要数天的烦琐工作才能解决, 而且他们容易犯错。”

在本章中,你将从编写一个程序开始,先不用正则表达式来寻找文本模式。 然后再看看,使用正则表达式让代码变得多么简洁。 我将展示用正则表达式进行基本匹配,然后转向一些更强大的功能,诸如字符串替换, 以及创建你自己的字符类型。

1.1. 不用正则表达式来查找文本模式

假设你希望在字符串中查找电话号码。你知道模式:3个数字, 一个短横线,3个数字,一个短横线,再是4个数字。 例如:415-555-4242。

假定我们用一个名为 isPhoneNumber() 的函数, 来检查字符串是否匹配模式,它返回 True 或 False 。 打开一个新的文件编辑器窗口,输入以下代码, 然后保存为 isPhoneNumber.py :

def isPhoneNumber(text):
if len(text) !=12:
return False
for i in range(3):
if not text[i].isdecimal():
return False
if text[3]!=‘-’:
return False
for i in range(4,7):
if not text[i].isdecimal():
return False
if text[7] != ‘-’:
return False
for i in range(8,12):
if not text[i].isdecimal():
return False
return True
print(‘415-555-4242 is a phone number:’)
print(isPhoneNumber(‘415-555-4242’))
print(‘Moshi moshi is a phone number:’)
print(isPhoneNumber(‘Moshi moshi’))
415-555-4242 is a phone number:
True
Moshi moshi is a phone number:
False
isPhoneNumber() 函数的代码进行几项检查, 看看 text 中的字符串是不是有效的电话号码。 如果其中任意一项检查失败,函数就返回 False 。 代码首先检查该字符串是否刚好有12个字符。 然后它检查区号(就是 text 中的前3个字符)是否只包含 数字。函数剩下的部分检查该字符串是否符合电话号码的模式: 号码必须在区号后出现第一个短横线), 3个数字,然后是另一个短横线,最后是4个数字。 如果程序执行通过了所有的检查,它就返回 True 。

用参数 ‘415-555-4242’ 调用 isPhoneNumber() 将返回真。 用参数 ‘Moshimoshi’ 调用 isPhoneNumber() 将返回假, 第一项测试失败了,因为不是12个字符。

必须添加更多代码,才能在更长的字符串中寻找这种文本模式。 用下面的代码, 替代 isPhoneNumber.py 中最后4个 print() 函数调用:

message=‘Call me at 415-555-1011 tomorrow.415-555-9999 is my office.’
for i in range(len(message)):
chunk=message[i:i+12]
if isPhoneNumber(chunk):
print(‘Phone number found:’ + chunk)
print(‘Done’)
Phone number found:415-555-1011
Phone number found:415-555-9999
Done
该程序运行时,输出看起来像这样:

在 for 循环的每一次迭代中, 取自 message 的一段新的12个字符被赋给变量 chunk() 。 例如,在第一次迭代, i 是 0 , chunk 被赋值为 message[0:12] (即字符串’Call me at 4’)。在下一次迭代, i 是1, chunk 被赋值为 message[1:13] (字符串 ‘all me at 41’ )。

将 chunk 传递给 isPhoneNumber(), 看看它是否符合电话号码的模式。如果符合, 就打印出这段文本。

继续遍历 message ,最终 chunk 中的12个字符会是一个电话号码。 该循环遍历了整个字符串,测试了每一段12个字符, 打印出所有满足 isPhoneNumber() 的 chunk 。 当我们遍历完 message ,就打印出 Done 。

在这个例子中,虽然 message 中的字符串很短, 但它也可能包含上百万个字符,程序运行仍然不需要一秒钟。 使用正则表达式查找电话号码的类似程序, 运行也不会超过一秒钟,但用正则表达式编写这类程序会快得多。

1.2. 用正则表达式查找文本模式

如果你想在有分机的电话号码中快速查找电话号,例如415-555-4242 x99,该怎么办呢?

正则表达式,又称规则表达式,英语简称为 regex,是文本模式的描述方法,能帮助你方便的检查一个字符串是否与某种模式匹配。

例如,\d 是一个正则表达式,表示一位数字字符, 即任何一位0到9的数字。 Python 使用正则表达式 \d\d\d-\d\d\d-\d\d\d\d , 来匹配前面 isPhoneNumber()函数匹配的同样文本: 3个数字、一个短横线、3个数字、一个短横线、4个数字。 所有其他字符串都不能匹配 \d\d\d-\d\d\d-\d\d\d\d 正则表达式。

但正则表达式可以复杂得多。例如, 在一个模式后加上花括号包围的3 ({3}), 就是说,“匹配这个模式3次”。 所以较短的正则表达式 \d{3}-\d{3}-\d{4} , 也匹配正确的电话号码格式。

1.2.1. 创建正则表达式对象

Python 中所有正则表达式的函数都在 re 模块中。在交互式环境中输入以下代码,导入该模块:

import re
re 模块的 compile() 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。 该对象拥有一系列方法用于正则表达式匹配和替换。 例如,向 re.compile() 传入一个字符串值表示正则表达式, 它将返回一个 Regex 模式对象(简称为 Regex 对象)。

要创建一个 Regex 对象来匹配电话号码模式, 就在交互式环境中输入以下代码。

regobj = re.compile(‘\d\d\d-\d\d\d-\d\d\d\d’)
现在 regobj 变量包含了一个 Regex 对象。

1.2.2. 匹配 Regex 对象

Regex 对象的 search() 方法查找传入的字符串,寻找该正则表达式的所有匹配。 如果字符串中没有找到该正则表达式模式,search() 方法将返回None 。 如果找到了该模式,search() 方法将返回一个 Match 对象。 Match 对象有一个 group() 方法,它返回被查找字符串中实际匹配的文本。 例如,在交互式环境中输入以下代码:

mo = regobj.search(‘My number is 415-555-4242.’)
print('Phone number found: ’ + mo.group())
Phone number found: 415-555-4242
变量名 mo 是一个通用的名称,用于 Match 对象。

这里,我们将期待的模式传递给 re.compile() ,并将得到的 Regex 对象保存在 phoneNumRegex 中。 然后我们在 phoneNumRegex 上调用 search() ,向它传入想查找的字符串。查找的结果保存在变量 mo 中。 在这个例子里,我们知道模式会在这个字符串中找到,所以我们知道会返回一个 Match 对象。 知道 mo 包含一个 Match 对象,而不是空值 None ,我们就可以在 mo 变量上调用 group() ,返回匹配的结果。 将 mo.group() 写在打印语句中,显示出完整的匹配,即 415-555-4242 。

如果对象没找到,可以进行判断:

mo2 = regobj.search(‘my number is 41555433.’)
print(‘got’) if mo2 else print(‘not got’)
not got
向 re.compile() 传递原始字符串
回忆一下, Python 中转义字符使用倒斜杠()。 字符串 V 表示一个换行字符, 而不是倒斜杠加上一个小写的 n 。 你需要输入转义字符 \ ,才能打印出一个倒斜杠。 所以 ‘\n’ 表示一个倒斜杠加上一个小写的 n 。 但是,通过在字符串的第一个引号之前加上 r , 可以将该字符串标记为原始字符串,它不包括转义字符。

因为正则表达式常常使用倒斜杠, 向 re.compile() 函数传入原始字符串就很方便, 而不是输入额外得到斜杠。输入 r’\d\d\d-\d\d\d-\d\d\d\d’ , 比输入 ‘\d\d\d-\d\d\d-\d\d\d\d’ 要容易得多。

1.2.3. 正则表达式匹配复习

虽然在 Python中使用正则表达式有几个步骤, 但每一步都相当简单。

用 import re 导入正则表达式模块。

用 re.compile() 函数创建一个 Regex 对象(记得使用原始字符串)。

向 Regex 对象的 search() 方法传入想查找的字符串。它返回一个 Match 对象。

调用 Match 对象的 group() 方法,返回实际匹配文本的字符串。

下面主要介绍Python中常用的正则表达式处理函数。

1.2.4. re.match函数

re.match() 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话, match() 就返回 None 。

函数语法:

re.match(pattern, string, flags=0)
函数参数说明:

pattern 匹配的正则表达式

string 要匹配的字符串。

flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

我们可以使用 group(num) 或 groups() 匹配对象函数来获取匹配表达式。

group(num=0) 匹配的整个表达式的字符串, group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。

groups() 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。

实例 1:

在起始位置匹配

print(re.match(‘www’, ‘www.runoob.com’).span())
(0, 3)
不在起始位置匹配

print(re.match(‘com’, ‘www.runoob.com’))
None

1.2.5. re.search方法

re.search 扫描整个字符串并返回第一个成功的匹配。

函数语法:

re.search(pattern, string, flags=0)
函数参数说明:

参数 | 描述

pattern | 匹配的正则表达式

string | 要匹配的字符串。

flags | 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

匹配成功 re.search 方法返回一个匹配的对象,否则返回None。

我们可以使用 group(num) 或 groups() 匹配对象函数来获取匹配表达式。

匹配对象方法 | 描述

group(num=0) |匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。

groups() | 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。

实例 1:

在起始位置匹配

print(re.search(‘www’, ‘www.runoob.com’).span())
(0, 3)
不在起始位置匹配

print(re.search(‘com’, ‘www.runoob.com’).span())
(11, 14)
实例 2:

import re

line = “Cats are smarter than dogs”;

searchObj = re.search(‘(.) are (.?) .*’, line, re.M|re.I)

if searchObj:
print ("searchObj.group() : ", searchObj.group())
print ("searchObj.group(1) : ", searchObj.group(1))
print ("searchObj.group(2) : ", searchObj.group(2))
else:
print (“Nothing found!!”)
searchObj.group() : Cats are smarter than dogs
searchObj.group(1) : Cats
searchObj.group(2) : smarter
instr = ‘/home/bk/book-rst/doculet/sphinx-tutorial/runoob-src/pt01_language_eb00kh’
re_book = re.compile(‘eb\d\d…’)
uu = re_book.search(instr)
uu.span()
(67, 73)
dir(uu)
[‘class’,
class_getitem’,
copy’,
deepcopy’,
delattr’,
dir’,
doc’,
eq’,
format’,
ge’,
getattribute’,
getitem’,
getstate’,
gt’,
hash’,
init’,
init_subclass’,
le’,
lt’,
module’,
ne’,
new’,
reduce’,
reduce_ex’,
repr’,
setattr’,
sizeof’,
str’,
subclasshook’,
‘end’,
‘endpos’,
‘expand’,
‘group’,
‘groupdict’,
‘groups’,
‘lastgroup’,
‘lastindex’,
‘pos’,
‘re’,
‘regs’,
‘span’,
‘start’,
‘string’]
uu.group()
‘eb00kh’

1.2.6. re.match 与 re.search 的区别

re.match 只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回 None ; 而 re.search 匹配整个字符串,直到找到一个匹配。

实例:

import re

line = “Cats are smarter than dogs”;

matchObj = re.match( ‘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!!”)
No match!!
search --> matchObj.group() : dogs

1.2.7. 检索和替换

Python 的re模块提供了re.sub用于替换字符串中的匹配项。

语法:

re.sub(pattern, repl, string, count=0)
参数:

pattern : 正则中的模式字符串。

repl : 替换的字符串,也可为一个函数。

string : 要被查找替换的原始字符串。

count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。

实例:

#!/usr/bin/python3
import re

phone = “2004-959-559 # 这是一个电话号码”

删除注释

num = re.sub(‘#.*$’, “”, phone)
print ("电话号码 : ", num)

移除非数字的内容

num = re.sub(‘\D’, “”, phone)
print ("电话号码 : ", num)
电话号码 : 2004-959-559
电话号码 : 2004959559

1.2.8. repl 参数是一个函数

以下实例中将字符串中的匹配的数字乘于 2:

#!/usr/bin/python

import re

将匹配的数字乘于 2

def double(matched):
value = int(matched.group(‘value’))
return str(value * 2)

s = ‘A23G4HFD567’
print(re.sub(‘(?P\d+)’, double, s))
A46G8HFD1134

1.2.9. 正则表达式修饰符 - 可选标志

正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:

修饰符 | 描述

re.I 使匹配对大小写不敏感

re.L 做本地化识别(locale-aware)匹配

re.M 多行匹配,影响 ^ 和 $

re.S 使 . 匹配包括换行在内的所有字符

re.U 根据Unicode字符集解析字符。这个标志影响 \w , \W , \b , \B .

re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。

1.2.10. 正则表达式模式

模式字符串使用特殊的语法来表示一个正则表达式:

字母和数字表示他们自身。一个正则表达式模式中的字母和数字匹配同样的字符串。

多数字母和数字前加一个反斜杠时会拥有不同的含义。

标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。

反斜杠本身需要使用反斜杠转义。

由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。 模式元素(如 r’/t’ ,等价于’//t’ )匹配相应的特殊字符。

下表列出了正则表达式模式语法中的特殊元素。如果你使用模式的同时提供了可选的标志参数,某些模式元素的含义会改变。

模式 | 描述

^ 匹配字符串的开头

$ 匹配字符串的末尾。

. 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。

[…] 用来表示一组字符,单独列出: [amk] 匹配 ‘a’,‘m’或’k’

[^…] 不在[]中的字符: [^abc] 匹配除了a,b,c之外的字符。

re* 匹配0个或多个的表达式。

re+ 匹配1个或多个的表达式。

re? 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式

re{ n}

re{ n,} 精确匹配n个前面表达式。

re{ n, m} 匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式

a|b 匹配a或b

(re) G匹配括号内的表达式,也表示一个组

(?imx) 正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。

(?-imx) 正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。

(?: re) 类似 (…), 但是不表示一个组

(?imx:re) 在括号中使用i, m, 或 x 可选标志

(?-imx: re) 在括号中不使用i, m, 或 x 可选标志

(?#…) 注释.

(?= re) 前向肯定界定符。如果所含正则表达式,以 … 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。

(?! re) 前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功

(?> re) 匹配的独立模式,省去回溯。

\w 匹配字母数字

\W 匹配非字母数字

\s 匹配任意空白字符,等价于 [\t\n\r\f] .

\S 匹配任意非空字符

\d 匹配任意数字,等价于 [0-9] .

\D 匹配任意非数字

\A 匹配字符串开始

\Z 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。c

\z 匹配字符串结束

\G 匹配最后匹配完成的位置。

\b 匹配一个单词边界,也就是指单词和空格间的位置。例如, er\b 可以匹配 never 中的 er , 但不能匹配 verb 中的 er 。

\B 匹配非单词边界。‘er:raw-latex:B’ 能匹配 “verb” 中的 ‘er’,但不能匹配 “never” 中的 ‘er’。

\n, \t , 等. 匹配一个换行符。匹配一个制表符。等

\1…\9 匹配第n个分组的内容。

\10 匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。

正则表达式符号复习
本章介绍了许多表示法,所以这里快速复习一下学到的内容:

? 匹配零次或一次前面的分组。

  • 匹配零次或多次前面的分组。

+匹配一次或多次前面的分组。

{n}匹配 n 次前面的分组。

{n,} 匹配 n 次或更多前面的分组。

{,m} 匹配零次到 m 次前面的分组。

{n,m}匹配至少 n 次、至多 m 次前面的分组。

{n,m}? 或 *? 或 +? 对前面的分组进行非贪心匹配。

^spam 意味着字符串必须以 spam 开始。

spam$意味着字符串必须以 spam 结束。

.匹配所有字符,换行符除外。

\d 、 \w和\s 分别匹配数字、单词和空格。

\D、\W和 \S分别匹配出数字、单词和空格外的所有字符。

[abc] 匹配方括号内的任意字符(诸如a、b或c)。

[^abc] 匹配不在方括号内的任意字符。文章来源地址https://www.toymoban.com/news/detail-732194.html

到了这里,关于【Python】Python 模式匹配与正则表达式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python正则表达式之学习正则表达式三步曲

            正则表达式描述了一种字符串匹配的模式,可以用来检查一个串的有无某子串,或者做子串匹配替换,取出子串等操作。也可以说正则表达式就是字符串的匹配规则,也可以理解为是一种模糊匹配,匹配满足正则条件的字符串。         1、数据验证(eg:表单验

    2024年02月15日
    浏览(44)
  • Java 正则表达式匹配

    正则表达式: 定义一个搜索模式的字符串。 正则表达式可以用于搜索、编辑和操作文本。 正则对文本的分析或修改过程为:首先正则表达式应用的是文本字符串(text/string),它会以定义的模式从左到右匹配文本,每个源字符只匹配一次。 正则表达式 匹配 this is text 精确匹配

    2024年02月06日
    浏览(42)
  • 正则表达式的神奇世界:表达、匹配和提取

    正则表达式,这个看起来像密林中的迷宫的工具,既神秘又令人着迷。它是编程世界中的一门魔法,有着神奇的能力。你是否曾经在寻找或解析文本时感到束手无策?或许你想要从海量数据中提取特定信息?这正是正则表达式可以派上用场的时候。本文将带你探索这个神奇的

    2024年02月07日
    浏览(44)
  • VSCode 正则表达式 匹配多行

    VS Code 正则表达式匹配多行 (.|n)*? 案例1: str(.|n)*?, 案例2: const(.|n)*?}$ 案例3: fn(.|n)*?},

    2024年02月02日
    浏览(34)
  • python正则表达式-正则基础

    目录 一、任一元素 二、匹配特定的字符类别          1、d  w 三、多个元素          1、两位元素 [][]          2、* + ?          3、重复次数 {}          4、位置匹配 ^ $          5、子表达式()         []:1、[ab] 匹配a或b;        2、[0-9] 匹配任意一个数

    2024年02月05日
    浏览(32)
  • 老夫的正则表达式大成了,桀桀桀桀!!!【Python 正则表达式笔记】

    特殊字符 .^$?+*{}[]()| 为特殊字符,若想要使用字面值,必须使用 进行转义 字符类 [] [] 匹配包含在方括号中的任何字符。它也可以指定范围,例: [a-zA-Z0-9] 表示a到z,A到Z,0到9之间的任何一个字符 [u4e00-u9fa5] 匹配 Unicode 中文 [^x00-xff] 匹配双字节字符(包括中文) 在 [] 中

    2024年02月04日
    浏览(45)
  • 【动态规划】通配符匹配与正则表达式匹配

    题目描述: 给你一个输入字符串 (s) 和一个字符模式 § ,请你实现一个支持 ‘?’ 和 ‘*’ 匹配规则的通配符匹配: ‘?’ 可以匹配任何单个字符。 ‘*’ 可以匹配任意字符序列(包括空字符序列)。 判定匹配成功的充要条件是:字符模式必须能够 完全匹配 输入字符串(而

    2024年02月07日
    浏览(42)
  • python 正则表达式

    2024年01月17日
    浏览(36)
  • PYthon正则表达式

    正则表达式是对字符串(包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为“元字符”))操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。正则

    2024年01月17日
    浏览(34)
  • 详解正则表达式匹配方法 match()

    在前端开发中,正则表达式是一大利器。所以我们这次就来讨论下match()方法。 match本身是JavaScript语言中字符串对象的一个方法,该方法的签名是 match([string] | [RegExp]) 它的参数既可以是一个字符串,也可以是一个正则表达式。该方法绝大多数都是要使用正则表达式的,所以参

    2024年02月11日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包