说明
《Python 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
本需求是需要将将 Python 中一个字符串中的所有字母用它的后继字母代替,比如,a 用 b 代替,b 用 c 代替,hello 替换为 iffmp。同时,非 26 个英文字母不作处理。
由于需求输入的类型是字符串,它是一个序列类型, 我们可以使用迭代的方法按逻辑对其进行循环处理,这样就变成了对单个字符的处理。
单个字符的处理逻辑包括:
明确了需求和思路,我们寻求解决方案。
关于英文字母信息,有几个可以帮助我们解决的 Python 内置模块和方法:
另外,下边还会用到 Python 和 pandas 的 map 和 replace 方法,可查看盖若网站上的相关教程。
我们用最原始的方法循环处理,根据以边的分析思路代码如下:
import string
def next_letters(letters):
new_letters = []
for i in letters:
# 非字母不处理
if i in string.ascii_letters:
# z 字母的后继为 a, 同时处理大小写问题
if i in ['z', 'Z']:
new_letters.append('A' if i.isupper() else 'a')
else:
foo = chr(ord(i)+1)
new_letters.append(foo)
# 非字母原样输出
else:
new_letters.append(i)
return ''.join(new_letters)
执行结果:
next_letters('Say hello, Zero!')
# 'Tbz ifmmp, Afsp!
next_letters('Z世代')
# 'A世代'
要注意的是, str.isalpha() 汉字也会返回 True,因些我们使用了字母表对比方法,判断字符是否在大小写字母表里边。
可以用 Python 的列表推导式方法快速实现这个需求,过程如下:
import string
# 构造一个字母字符串,后一个是需求中前一个的后继字母
letters = string.ascii_lowercase + 'a' + string.ascii_uppercase + 'A'
letters
# 'abcdefghijklmnopqrstuvwxyzaABCDEFGHIJKLMNOPQRSTUVWXYZA'
# 查找指定字母后继字母方法
letters[letters.find('Z')+1]
# 'A'
# 完成操作
''.join([letters[letters.find(i)+1] if i in [*letters] else i for i in 'Say hello, Zero!' ])
# 'Tbz ifmmp, Afsp!'
''.join([letters[letters.find(i)+1] if i in [*letters] else i for i in 'Z世代' ])
# 'A世代'
这是比较短平快的实现方式。
我们将需要替换的字母关系生成一个字典,然后再 map 这个字符串。过程代码如下:
import string
# 包含所有ASCII小写字母的字符串
string.ascii_lowercase
# 'abcdefghijklmnopqrstuvwxyz'
# 包含所有ASCII大写字母的字符串
string.ascii_uppercase
# 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
# 大小写字母列表组装
lower_map = zip(string.ascii_lowercase, string.ascii_lowercase[1:]+'a')
upper_map = zip(string.ascii_uppercase, string.ascii_uppercase[1:]+'A')
# 查看其中一个的结果
list(lower_map)
'''
[('a', 'b'),
('b', 'c'),
('c', 'd'),
...
('y', 'z'),
('z', 'a')]
'''
# 可以将元组列表直接转为字典
dict(upper_map)
'''
{'A': 'B',
'B': 'C',
'C': 'D',
'D': 'E',
...
'Y': 'Z',
'Z': 'A'}
'''
# 最终将大小写两个字典合并为一个字典
letters_map = {**dict(upper_map), **dict(lower_map)}
letters_map
'''
{'A': 'B',
'B': 'C',
'C': 'D',
...
'y': 'z',
'z': 'a'}
'''
# map 字符串,如果无法映射,返回原字符串
''.join(map(lambda x: letters_map.get(x, x), 'Say hello, Zero!'))
# 'Tbz ifmmp, Afsp!
''.join(map(lambda x: letters_map.get(x, x), 'Z世代'))
# 'A世代'
要注意的是,upper_map 和 lower_map 是 zip 对象,是一个可迭代对象,它只能使用一次,字典合并时要重新给 upper_map 和 lower_map 赋值。
最终封装一个函数,代码如下:
import string
def next_letters(letters):
lower_letters = string.ascii_lowercase
upper_letters = string.ascii_uppercase
# 拼装有对应关系的大小写字母表
lower_map = zip(lower_letters, lower_letters[1:]+'a')
upper_map = zip(upper_letters, upper_letters[1:]+'A')
# 转为字典并合并一个统一的字典
letters_map = {**dict(upper_map), **dict(lower_map)}
# 将 map 处理后的字符串拼结并返回
return ''.join(map(lambda x: letters_map.get(x, x), letters))
# 执行效果
next_letters('Say hello, Zero!')
# 'Tbz ifmmp, Afsp!
next_letters('Z世代')
# 'A世代'
这个方法少了 for 循环,大大降低了复杂度,逻辑也更加清晰,代码更明确。
由于需求中处理的是字符串是序列,上个方案我们也用到了 map 机制,那么我们能不能直接使用 pandas 的 Series 的映射替换处理方案来完成需求呢,这就试试看!
import pandas as pd
import string
# 包含所有ASCII字母的字符串
string.ascii_letters
# 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
# 先构造映射 Series
letters_map = pd.Series([*string.ascii_letters])
letters_map
'''
0 a
1 b
2 c
...
50 Y
51 Z
dtype: object
'''
# 处理数据完成构造
letters_map = (
letters_map.rename(letters_map) # 将索引也设置为此序列
.shift(-1) # 值往前移动,代表下个字母
.mask(lambda x: x.index=='z', 'a') # 将 z 替换为 a
.mask(lambda x: x.index=='Z', 'A') # 同上,替换大写
)
letters_map
'''
a b
b c
c d
...
Y Z
Z A
dtype: object
'''
# 应用
(
pd.Series([*'Say hello, Zero!'])
.replace(letters_map)
.pipe(''.join)
)
# 'Tbz ifmmp, Afsp!'
封装为函数,最终代码为:
import pandas as pd
import string
def next_letters(letters):
# 读取大小写字母表
letters_map = pd.Series([*string.ascii_letters])
# 构造映射 Series
letters_map = (
letters_map.rename(letters_map) # 将索引也设置为此序列
.shift(-1) # 值往前移动,代表下个字母
.mask(lambda x: x.index=='z', 'a') # 将 z 替换为 a
.mask(lambda x: x.index=='Z', 'A') # 同上,替换大写
)
# 将字符读取到 Series 进行处理,并返回
return (
pd.Series([*letters])
.replace(letters_map)
.pipe(''.join)
)
# 应用函数
next_letters('Say hello, Zero!')
# 'Tbz ifmmp, Afsp!
next_letters('Z世代')
# 'A世代'
pandas 处理让逻辑更加清晰,代码更加流畅,但前提是你需要熟练使用 pandas。
(完)
更新时间:2024-08-18 16:33:21 标签:python 字符串 替换