接着昨天的分享我们继续往下看
目录
1.字符串忽略大小写搜索替换
问题:替换字符串里面的内容,且这个内容存在大写和小写
思路:在re模块中,可以给字符串提供re.IGNORECASE标志参数,即可解决问题
代码实现:
text = 'I like Python,because python,very PYTHON'
find_python = re.findall('python',text,re.IGNORECASE)
print(find_python) # ['Python', 'python', 'PYTHON']
replace_python = re.sub('python','java',text,flags=re.IGNORECASE)
print(replace_python) # I like java,because java,very java
注意:可以使用位置传参和关键字传参,关键就在于给flags传入标志参数。默认情况下,flags为none。
延伸:如果我们想替换的字符串也和原先的字符串大小写保持一致怎么做呢,因为目前的替换智能替换成固定的java,我想替换成 “I like Java,because java,very JAVA”怎么实现,我们可以自定义一个辅助函数实现
代码实现:
text = 'I like Python,because python,very PYTHON'
def wraping(word):
def replace(m):
text = m.group()
print(text)
if text.isupper():
return word.upper()
elif text.islower():
return word.lower()
elif text[0].isupper():
return word.capitalize()
else:
return word
return replace
new_text = re.sub('python',wraping('java'),text,flags=re.IGNORECASE)
print(new_text) # I like Java,because java,very JAVA
解释:以上辅助函数是一个闭包,结合我们的sub方法,其原理就是从text中搜索python字符串,进入到里层函数的时候,把搜索到的分为一组,然后去判断当前的这个python的几种情况,如果都是大写,那么我们传入的这个word也是大写,如果都是小谢,那我我们的这个word也就都是小写,如果开头是大写,那么我们的word就首字母大写,其他情况正常返回word即可,最后,外部函数的返回内部的引用,完成闭包辅助。
思考:既然闭包可以解决这个问题,那么我们在代码上稍作修改,就可以用装饰器来解决了,有感兴趣的可以和我私下沟通哦。
2.最短匹配模式
问题:现在要用正则去匹配最短的符合条件的字符串,因为在正则里面 * 代表贪婪匹配,即不确定的情况下,全部匹配。
思路:一般这种问题用于匹配一种对称的分隔符,比如双引号或者单引号,详细看下面代码
代码实现:
text1 = 'I say "yes."'
new_text1 = re.findall(r'\"(.*)\"',text1)
print(new_text1) # ['yes.']
text2 = 'I say "yes.",you say "no."'
new_text2 = re.findall(r'\"(.*)\"',text2)
print(new_text2) # ['yes.",you say "no.']
延伸:这个正则意在匹配两个双引号之间的所有文本,很显然,第二个new_text2不是我们预期的结果。怎么解决呢?正则匹配中加入?即可解决
代码如下:
text1 = 'I say "yes."'
new_text1 = re.findall(r'\"(.*)\"',text1)
print(new_text1) # ['yes.']
text2 = 'I say "yes.",you say "no."'
new_text2 = re.findall(r'\"(.*?)\"',text2)
print(new_text2) # ['yes.', 'no.']
解释:这样我们的匹配方式就变成了非贪婪匹配,就得到了我们想要的结果了。另外延伸一点就是,在我们的python爬虫中,经常会用到正则的使用方法,因为要解析前端网页的元素,在进行快速解析匹配有效元素的时候经常会用到这个“.*?”,希望大家对这个能有所敏感
3.多行匹配模式
问题:使用正则去匹配一堆文本,且这个文本跨行
思路:因为我们正则里面的(.)是可以去匹配任意字符的,但是我们的换行符却不能被匹配进去,所以只需要解决能匹配换行符的问题即可解决这个问题。
代码实现:
text3 = '''
/* this is a
boy in hangzhou */
'''
new_text3 = re.findall(r'/\*((?:.|\n)*?)\*/',text3)
print(new_text3) # [' this is a\n boy in hangzhou ']
解释:“((?:.|\n)*?)”主要观察这个正则匹配,这个就是把一开始的.*?中的.修改了一下,就是除了匹配前面的所有字符以外,还要匹配\n换行符
4.将Unicode文本标准化
问题:处理Unicode字符串,使其所有的字符串在底层有相同的表示
思路:Unicodedata即可解决这个问题
代码实现:
a = 'chain Love\u00f1o'
b = 'chain Loven\u0303o'
print(a) # chain Loveño
print(b) # chain Loveño
print(a == b) # False
import unicodedata
t1 = unicodedata.normalize('NFC',a)
t2 = unicodedata.normalize('NFC',b)
print(t1) # chain Loveño
print(t2) # chain Loveño
print(t1 == t2) # True
解释:可以发现不同的Unicode编码出来的结果表面上看上去是一样的,但是实则他们所占用的内存空间不一样,编码格式决定了其字符占位大小。但是为了统一,我们就可以用unicodedata.normalize来解决。看一下我们的normalize源码:
def normalize(*args, **kwargs): # real signature unknown
"""
Return the normal form 'form' for the Unicode string unistr.
Valid values for form are 'NFC', 'NFKC', 'NFD', and 'NFKD'.
"""
pass
解释:返回Unicode字符串的标准格式表单。表单的有效值为“NFC”、“NFKC”、“NFD”和“NFKD”。所以我们的*args可以传以上表单内容来讲Unicode标准化
5.结束语
今天的内容我觉得还挺难得,但是只要掌握其中的原理,理解设计思路。至于其中的一些小方法可以下去多练练,多研究就记住了。这篇文章我有一些地方也是参考了一些博客创作的。如有不对的地方,欢迎大佬来指正,我们下一篇见。