Python 字符串匹配、搜索及替换 | 您所在的位置:网站首页 › python替换字符串中的字符for › Python 字符串匹配、搜索及替换 |
文章目录
字符串匹配、搜索及替换字符串开头或结尾匹配str.startswith() 和 str.endswith()
用 Shell 通配符匹配字符串fnmatch() 和 fnmatchcase()
字符串匹配和搜索str.find()正则表达式及 re 模块re.match()re.compile()re.findall()re.finditer()
字符串搜索和替换str.replace()re.sub()re.subn()
字符串匹配、搜索及替换
在处理字符串中,有时会需要定位字符串,然后对字符串进行相应的处理。 字符串开头或结尾匹配对于字符串的检查,可以通过特定的文本模式进行匹配。在 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,如果有 list 和 set 类型的选项,可以使用 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)正则表达式方法放在这里,的确能够解决问题,但是有点大材小用。而且,Python 内置的 startswith() 和 endswith() 方法,对于这种简单匹配运行会更快。 用 Shell 通配符匹配字符串除了通过你内置类型的方法对字符串进行匹配,还可以使用 Unix Shell 中的常用的通配符(比如 *.py,Dat[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') Falsefnmatch() 函数匹配的能力介于简单字符串方法和正则表达式之间。如果在数据处理操作中,能够用简单通配符匹配的情况下,这是一个可以考虑的方案。 如果需求中需要做文件名的匹配,建议使用 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 模块对于一些复杂的匹配,则需要借助正则表达式1和 re 模块。 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 >>> 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 >>> 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') >>>上面的代码并未匹配 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 >>>以上就是本篇的主要内容。 结语: 新年快乐! 可参考【正则表达式 笔记整理】 ↩︎ |
CopyRight 2018-2019 实验室设备网 版权所有 |