Python 字符串匹配、搜索及替换

本文深入探讨了Python中字符串的匹配与替换方法,包括str.startswith(), str.endswith(), str.find(), str.replace()等内置方法,以及使用正则表达式进行复杂模式匹配的re模块函数如re.match(), re.compile(), re.findall(), re.finditer(), re.sub()和re.subn()。同时介绍了Shell通配符匹配函数fnmatch()和fnmatchcase(),以及它们在不同操作系统下的大小写敏感特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

字符串匹配、搜索及替换


在处理字符串中,有时会需要定位字符串,然后对字符串进行相应的处理。

字符串开头或结尾匹配


对于字符串的检查,可以通过特定的文本模式进行匹配。在 Python 内置类型中也提供了 str.startswith()str.endswith() 方法对字符串进行开头或结尾的检查。

str.startswith() 和 str.endswith()

str.startswith()str.endswith() 是检查字符串开头或结尾的一个简单方法。例如文件的后缀,URL 跳转协议,示例如下:

>>> filename = "string.txt"
>>> filename.endswith('.txt')
True
>>> filename.startswith('file:')
False
>>> url = 'http://www.python.org'
>>> url.startswith('http:')
True

如果要检查多种匹配的可能,可以提供一个元组,将所有的匹配项写入元组中,然后传给 startswith()endswith() 方法的第一个参数中:

>>> import os
>>> filenames = os.listdir('.')
>>> filenames
['tools', 'list_links.txt', 'access_test.py', 'control_roll.py', 'access.log', 'data.xls']
>>> [name for name in filenames if name.endswith(('.py', '.txt'))]
['list_links.txt', 'access_test.py', 'control_roll.py']
>>> any(name.endswith('.py') for name in filenames)
True

这里需要说明的是startswith()endswith() 两个方法的第一个参数,如果是要传入多种匹配选项,需要传入的类型必须是 tuple,如果有 listset 类型的选项,可以使用 tuple() 方法将已有选项进行转换。

上面提及的 startswith()endswith() 方法有一种替代的方法,就是切片操作,但是代码看起来会相对繁冗。示例如下:

>>> filename = 'string.txt'
>>> filename[-4:] == '.txt'
True
>>> url = 'http://www.python.org'
>>> url[:5] == 'http:' or url[:6] == 'https:' or url[:4] == 'ftp:'
True

还有另外一种方法是通过正则表达式去实现,示例如下:

>>> import re
>>> url = 'http://www.python.org'
>>> re.match('http:|https:|ftp:', url)
<_sre.SRE_Match object; span=(0, 5), match='http:'>

正则表达式方法放在这里,的确能够解决问题,但是有点大材小用。而且,Python 内置的 startswith()endswith() 方法,对于这种简单匹配运行会更快。

用 Shell 通配符匹配字符串


除了通过你内置类型的方法对字符串进行匹配,还可以使用 Unix Shell 中的常用的通配符(比如 *.pyDat[0-9]*.csv 等)去匹配字符串。

fnmatch() 和 fnmatchcase()

Python 提供的 fnmatch 模块就有两个函数 fnmatch()fnmatchcase() 可以用来实现这样的匹配。示例如下:

>>> from fnmatch import fnmatch, fnmatchcase
>>> fnmatch('string.txt','*.txt')
True
>>> fnmatch('string.txt','?ing.txt')
False
>>> fnmatch('string.txt','?tring.txt')
True
>>> fnmatch('Dat57.csv','Dat[0-9]*')
True
>>> names = ['Dat1.csv','Dat2.csv','config.ini','test.py']
>>> [name for name in names if fnmatch(name, 'Dat*.csv')]
['Dat1.csv', 'Dat2.csv']

但是需要注意的是 fnmatch() 函数,在使用不同的底层操作系统的大小写敏感规则是不同的。这里是因为这个函数中的形参都会使用 os.path.normcase() 进行大小写正规化,在 Linux,Mac 中,会原样返回;而在 Windows 中,这里会将字符转换为小写返回。示例如下:

>>> # On Mac
>>> fnmatch('string.txt', '*.TXT')
False
>>> # On Windows
>>> fnmatch('string.txt', '*.TXT')
True

如果对于这个大小写敏感规则很在意的情况下,可以使用 fnmatchcase() 来替代。这个函数完全区分大小写。示例如下:

>>> fnmatchcase('string.txt', '*TXT')
False

fnmatch() 函数匹配的能力介于简单字符串方法和正则表达式之间。如果在数据处理操作中,能够用简单通配符匹配的情况下,这是一个可以考虑的方案。

如果需求中需要做文件名的匹配,建议使用 glob 模块中的方法。具体的使用方法可参考下面的官方文档:

https://docs.python.org/3.6/library/glob.html

字符串匹配和搜索


如果需要匹配的字符串比较简单,通常情况下,需要调用基本字符串方法就可以。

str.find()

除了前面介绍的 str.endswith()str.startswith() 的方法,还有 str.find() 方法,这个方法用于查找匹配项第一次出现的位置,这些都能够实现简单的匹配搜索,示例如下:

>>> text = 'yeah, but no, but yeah, but no, but yeah'
>>> # 匹配开头或结尾
...
>>> text.startswith('yeah')
True
>>> text.endswith('no')
False
>>> # 搜索第一次出现位置
...
>>> text.find('no')
10

正则表达式及 re 模块


对于一些复杂的匹配,则需要借助正则表达式1re 模块。

re.match()

下面举例简单介绍匹配数字格式的日期字符串,示例如下:

>>> text1 = '11/27/2012'
>>> text2 = 'Nov 27, 2012'
>>> import re
>>> # 简单匹配一个或多个数字
...
>>> if re.match(r'\d+/\d+/\d+', text1):
...     print('yes')
... else:
...     print('no')
...
yes
>>> if re.match(r'\d+/\d+/\d+', text2):
...     print('yes')
... else:
...     print('no')
...
no
>>>
re.compile()

如果需要使用同个模式进行多次匹配,那么可以考虑将模式字符串编译为模式对象。re.compile() 提供编译正则表达式字符串,示例如下:

>>> pattern = re.compile(r'\d+/\d+/\d+')
>>> if re.match(pattern, text1):
...     print('yes')
... else:
...     print('no')
...
yes
>>> if re.match(pattern, text2):
...     print('yes')
... else:
...     print('no')
...
no
re.findall()

match() 方法总是从字符串开始去匹配,如果查找字符串任意部分出现的位置,建议使用 findall() 方法代替。示例如下:

>>> text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'
>>> pattern = r'\d+/\d+/\d+'
>>> re.findall(pattern, text)
['11/27/2012', '3/13/2013']
>>>

有时候定义正则表达式的时候,会利用括号进行捕获分组。示例如下:

>>> pattern = re.compile(r'(\d+)/(\d+)/(\d+)')
>>>

捕获分组的用处主要是用于将每个组的内容提取出来,也对后续的处理进行备用。示例如下:

>>> import re
>>> pattern = re.compile(r'(\d+)/(\d+)/(\d+)')
>>> match_data = re.match(pattern,'11/27/2012')
>>> match_data
<_sre.SRE_Match object; span=(0, 10), match='11/27/2012'>
>>> match_data.group(0)
'11/27/2012'
>>> match_data.group(1)
'11'
>>> match_data.group(2)
'27'
>>> match_data.group(3)
'2012'
>>> match_data.groups()
('11', '27', '2012')
>>> month, day, year = match_data.groups()
>>> text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'
>>> # 使用 findall(),注意返回的结果是列表里面包裹元组
... re.findall(pattern, text)
[('11', '27', '2012'), ('3', '13', '2013')]
>>> for month, day, year in re.findall(pattern, text):
...     print('{}-{}-{}'.format(year, month, day))
...
2012-11-27
2013-3-13
re.finditer()

findall() 方法会以搜索文本并以列表形式返回所有的匹配。如果想以迭代的方式返回匹配,可以考虑使用 re.finditer() 方法代替。

re.finditer() 方法返回一个迭代器,方法是从左到右扫描字符串,按照找到匹配项的顺序返回,示例如下:

>>> for match_data in re.finditer(pattern, text):
...     print(match_data.groups())
...
('11', '27', '2012')
('3', '13', '2013')

综合上述,re 模块进行匹配和搜索文本,核心的步骤是先使用 re.compile() 将正则表达式字符串进行编译,然后根据需求使用 match()findall() 或者 finditer() 方法。

一些建议: 编写正则表达式字符串的时候,通常会是 r'' 这种形式,这种使用原始字符串的做法,能够不用去解析反斜杠。如果不这样做的话,需要使用两个反斜杠,例如:(\\d+/\\d+/\\d+)

注意事项: match() 方法仅仅检查字符串的开始部分, 匹配的结果可能并非期望的结果。示例如下:

>>> pattern = re.compile(r'(\d+)/(\d+)/(\d+)')
>>> match_data = re.match(pattern, '11/27/2012abcdef')
>>> match_data
<_sre.SRE_Match object; span=(0, 10), match='11/27/2012'>
>>> match_data.group()
'11/27/2012'

如果需要精确匹配,得在正则表达式以 $ 结尾,如下示例:

>>> pattern = re.compile(r'(\d+)/(\d+)/(\d+)$')
>>> re.match(pattern, '11/27/2012abcdef')
>>> re.match(pattern, '11/27/2012')
<_sre.SRE_Match object; span=(0, 10), match='11/27/2012'>
>>>

上面的代码并未匹配 11/27/2012abcdef,因为编译的正则表达式以 $ 结尾,说明必须精确匹配才会返回结果。

如果仅仅是做一次简单的文本匹配/搜索操作的话,可以略过编译部分,但是,需要进行大量的匹配和搜索操作的话,最好先对正则表达式字符串进行编译,然后再重复使用。这样做的原因是不会消耗太多的性能 。

字符串搜索和替换


对于字符串的搜索时,有时候会对搜索的匹配项进行替换操作。

str.replace()

如果是简单的字面模式,可以直接用 str.replace() 方法,示例如下:

>>> text = 'yeah, but no, but yeah, but no, but yeah'
>>> text.replace('yeah', 'yep')
'yep, but no, but yep, but no, but yep'
>>>

re.sub()

对于复杂的模式,请使用 re 模块中的 sub() 函数。现在的需求是这样,将形式为 11/27/2012 的日期字符串改为 2012-11-27,下面的是实现的代码:

>>> text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'
>>> import re
>>> re.sub(r'(\d+)/(\d+)/(\d+)', r'\3-\1-\2', text)
'Today is 2012-11-27. PyCon starts 2013-3-13.'

sub() 函数中,第一个参数表示的是被匹配的模式,第二个参数表示的是替换模式。反斜杠数字,比如 \3 指向的是前面模式捕获分组的组号。

如果打算用相同的模式做多次替换,同样可以考虑先编译再重复使用。

re.subn()

如果除了替换后的结果外,还需要知道进行了多少次替换,可以使用 re.subn() 来代替。比如:

>>> text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'
>>> pattern = re.compile(r'(\d+)/(\d+)/(\d+)')
>>> newtext, n = re.subn(pattern, r'\3-\1-\2', text)
>>> newtext
'Today is 2012-11-27. PyCon starts 2013-3-13.'
>>> n
2
>>>

以上就是本篇的主要内容。


结语: 新年快乐!


  1. 可参考【正则表达式 笔记整理↩︎

<think>好的,我现在需要帮助用户了解如何在Python中进行字符串匹配替换。用户的问题比较明确,但可能需要详细的方法说明和示例。首先,我需要回顾自己掌握的知识,并参考提供的引用资料,确保信息准确。 首先,根据用户提供的引用,引用了四种方法:str.replace()、正则表达式替换(re.sub)、re.findall,以及可能的其他方法。用户的问题包括匹配替换,所以需要涵盖这两个方面。 接下来,我需要整理这些方法,分步骤说明。可能需要分为基本替换方法、正则表达式替换、其他匹配方法等部分。同时,要确保每个方法都有代码示例,方便用户理解。 需要注意系统级指令中的格式要求:行内数学表达式用$...$,但这个问题可能不涉及数学公式,所以可能用不上。独立公式需要单独成段,但同样可能不适用。不过要确保LaTeX语法正确,这里可能涉及代码块的展示,所以需要正确使用代码标记。 用户要求回答结构清晰,逐步解决问题,所以应该分点说明,每个方法作为一个小节,包含说明、示例代码和适用场景。同时,要引用提供的参考资料,比如在str.replace()处引用[^1],正则表达式替换引用[^3],findall引用[^4]等。 需要检查是否有遗漏的方法。比如,除了str.replace()和re.sub,还有split和join的组合方法,或者translate方法,但根据引用资料,用户提供的引用中没有提到这些,可能不需要涉及。不过用户的问题是关于匹配替换,所以主要覆盖提到的几种方法即可。 在回答中,可能需要指出不同方法的优缺点,比如简单替换用str.replace(),复杂模式用正则表达式。同时,提醒用户注意正则表达式的性能问题,或者replace方法的多次替换问题。 现在开始组织内容: 1. 基本字符串替换方法:str.replace() - 说明:简单直接,适合固定字符串替换 - 示例代码 - 引用[^1]和[^2] 2. 正则表达式替换:re.sub() - 说明:处理复杂模式,如通配符、特定模式等 - 示例代码:比如替换所有数字,替换日期格式等 - 引用 3. 正则表达式匹配:re.findall() - 说明:提取所有匹配项,可能用于替换前的匹配检查 - 示例代码 - 引用 可能还需要补充其他相关方法,如re.match()和re.search()的区别,但用户的问题主要是替换,所以可能不需要深入,但可以简要提及。 然后,生成相关问题,比如如何替换多个不同字符串、如何忽略大小写替换等。 需要确保代码示例正确,比如在re.sub中使用正则表达式,例如替换所有数字为某个字符。此外,注意转义字符使用,比如在正则表达式中可能需要用r前缀。 最后,检查是否覆盖了用户的需求,是否有结构清晰,分点明确,引用正确。确保没有格式错误,如代码块使用```python,引用标识在正确的位置。</think>### Python字符串匹配替换方法教程 在Python中,字符串匹配替换可通过多种方法实现,具体选择取决于场景的复杂度。以下是常用方法及示例: --- #### 一、基本字符串替换:`str.replace()` 适用于**固定内容**的简单替换,无需复杂模式。 **语法**:`字符串.replace(旧子串, 新子串, 替换次数)` **示例**: ```python text = "Hello World! World is big." new_text = text.replace("World", "Python", 1) # 替换第一个"World" print(new_text) # 输出: Hello Python! World is big. ``` **说明**: - 默认替换所有匹配项,若需限制次数可指定第三个参数[^2]。 --- #### 二、正则表达式匹配替换:`re.sub()` 适用于**复杂模式**(如通配符、数字、特定格式等)。 **语法**:`re.sub(正则表达式, 新内容, 字符串, 替换次数)` **示例**: ```python import re text = "订单号:12345,金额:¥100.50" # 替换所有数字为* new_text = re.sub(r'\d+', '*', text) print(new_text) # 输出: 订单号:*****,金额:¥***.** # 替换日期格式(如2023-01-01为YYYY/MM/DD) text = "日期:2023-01-01" new_text = re.sub(r'(\d{4})-(\d{2})-(\d{2})', r'\1/\2/\3', text) print(new_text) # 输出: 日期:2023/01/01 ``` **说明**: - 使用`r''`定义正则表达式避免转义问题。 - 分组后可通过`\1`、`\2`引用匹配内容。 --- #### 三、正则表达式匹配:`re.findall()` 与 `re.search()` 用于**提取或验证**字符串中的模式。 1. **提取所有匹配项**:`re.findall()` ```python text = "邮箱:user1@example.com, user2@test.org" emails = re.findall(r'\b[\w.-]+@[\w.-]+\.\w+\b', text) print(emails) # 输出: ['user1@example.com', 'user2@test.org'] ``` 2. **验证是否存在匹配**:`re.search()` ```python text = "ID: A123B" if re.search(r'^[A-Z]\d{3}[A-Z]$', text): print("格式正确") ``` **说明**: - `re.findall()`返回所有匹配的列表,无匹配时返回空列表。 - `re.search()`返回第一个匹配对象,适合验证场景。 --- #### 四、其他实用技巧 1. **忽略大小写替换**: ```python text = "Python is Fun. PYTHON is easy." new_text = re.sub(r'python', 'Java', text, flags=re.IGNORECASE) print(new_text) # 输出: Java is Fun. Java is easy. ``` 2. **多重替换**: 若需替换多个不同内容,可结合字典与循环: ```python replacements = {"Apple": "Orange", "red": "blue"} text = "Apple is red." for old, new in replacements.items(): text = text.replace(old, new) print(text) # 输出: Orange is blue. ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值