字符串和文本 (02)
继续 PythonCookbook, 感觉我这波取名怪怪的, 字符串文本, 本质上其实一回事情. 哦, 恰好, 最近一个小伙伴说要转行数据这块, 再跟我探讨经验, 毕竟我是这样过来的. 嗯... 其实我特别害怕回答这个问题, 鼓励也不是, 不鼓励也不是. 从亲历来看, 确实不太容易, 要学的东西真的太多了, 只是稍微客观说了一下.
决定了,就要做好准备,转行其实,不太容易,尤其是专业技术这块,不可能速成,需要时间的积累.
然后关于学习方法啥的, 哪有什么技巧, 又不是大学考试, 临时突击... 这没有捷径的, 哪有速成, 只是, 付出的时间和精力太多了, 才慢慢有所领悟
故余虽愚, 卒获有所闻.
当然最后, 我也是说了下, 我所谓的方法, 其实就是花时间, 没有别的, 代码这块, 见多识广, 唯手熟尔.
我当时学的时候,比较蠢,就抄别人的代码,一股脑儿的抄,,,每天坚持抄,直到现在也是,抄的量比较大了,比如一年几万行,就慢慢理解了,自己就会写了.
当然,我现在也不怎么写了,主要是之前收藏了很多,抄抄改改就行了.
职业, 人生问题, 不必探讨; 技术细节,欢迎交流
扯远了, 回归正题, 关于字符串匹配, 搜索方面的小 tips.
字符串匹配和搜索
需求
对字符串进行搜索或匹配搜索, 依据特定模式.
方案
简单的用内置方法如 starswith(); endswith(); find(); rfind() 这些, 复杂的用 re 正则表达式, 能解决一切匹配问题.
text = "yeah, but no, but yeah, but no, but yeah"
# Exact math
text == 'yeah'
False
print(text.startswith('yeah'))
print(text.endswith('no'))
print(text.find('no'))
True
False
10
对于稍微复杂一些的就要用到正则表达式了. 比如这里我们先来匹配日期字符串如 05/20/2020 可以这样写.
import re
text_01 = "05/20/2020"
text_02 = "may,22,2020"
# "\d" 匹配数字; "+" 表示最少一次
if re.match(r"\d+/\d+/\d+", text_01):
print('yes')
else:
print('no')
print('yes') if re.match("\d+/\d+/\d+", text_02) else print("no")
yes
no
re.match() 匹配到, 返回的是是一个对象, 用 group() 方法可拿出了; 若无匹配到, 则返回 None. 而不直接报错, 鲁棒性还是可以的哦.
re.match(r"\d+/\d+/\d+", text_01).group()
'05/20/2020'
re.comple() 用于, 同一个模式, 做多次匹配的场景, 因为, 不可能重复写多次吧.
# re.compile() 用于多次重复匹配的情况
date_pat = re.compile(r"\d+/\d+/\d+")
print('yes') if date_pat.match(text_01) else print('no')
print('yes') if date_pat.match(text_02) else print('no')
yes
no
re.findall() 返回匹配成功的对象(任意位置), 以列表形式. 是我最常用的了. 与 re.match() 不同在于, match() 只是从字符串头部开始匹配, 一旦匹到就不再继续了.
text = "Today is 05/20/2020. My first Python Programming starts 4/20/2015"
print(date_pat.findall(text))
['05/20/2020', '4/20/2015']
通常还会利用括号去捕获分组. 分组的好处是可以让后面的处理更加简单, 分组提取了嘛.
date_pat = re.compile(r"(\d+)/(\d+)/(\d+)")
ret = date_pat.match("05/20/2020")
print(ret)
print(ret.group(0))
print(ret.group(1))
print(ret.group(2))
print(ret.group(3))
print(ret.groups())
print(date_pat.findall(text))
# 拆包
for month, day, year in date_pat.findall(text):
print(f"{year}-{month}-{day}")
<_sre.SRE_Match object; span=(0, 10), match='05/20/2020'>
05/20/2020
05
20
2020
('05', '20', '2020')
[('05', '20', '2020'), ('4', '20', '2015')]
2020-05-20
2015-4-
re.findall( ) 方法会搜索文本并以列表方式返回, 于是呢, 如果想用迭代的方式返回, 则用 re.finditer() 即可.
for m in date_pat.finditer(text):
print(m.groups())
('05', '20', '2020')
('4', '20', '2015')
注意一点是, re.match() 方法, 仅仅是检查字符串开始的部分, 对于结尾并没有限定, 如果是想要更加精确, 则 用 '$'
date_pat = re.compile(r"(\d+)/(\d+)/(\d+)$")
字符串搜索替换
需求
在字符串中, 对指定的文本进行搜索和替换
方案
同样对于简单的模式, 直接用 str.replace( ) 即可. 复杂的用 re.sub( )
text = "yeah, but no, but yeah, but no, but yeah"
text.replace('yeah', '520')
'520, but no, but 520, but no, but 520'
re.sub (pattern, repl, string,...) 有3个重要的参数, 第一个是匹配模式, 第二个是用来替换的 字符串; 第三个是目标字符串.
import re
text = "Today is 05/20/2020. My first Python Programming starts 4/20/2015"
re.sub(r"(\d+)/(\d+)/(\d+)", "520", text)
'Today is 520. My first Python Programming starts 520'
小结
- 字符串查找替换, 优先考虑内置方法, 如 startswith(), endswith(), replace() ...
- 复杂的用正则, re.math(); re.findall(); re.sub(); re.compile( ) , 分组 group 等非常常用的
- 最后就是字符串正则...特别灵活和重要且强大, 必须要会编写哦.