s = '1班' + '看见星光'
s = '看见星光' + str(59)
字符串的join()方法可以将序列中的元素以指定的分隔符连接成一个新的字符串,基本语法如下:
str.join(iterable)
str是指定的分隔符,iterable是一个可迭代对象,其元素必须为字符串,如果其中包含了非字符串,会导致代码抛出异常:TypeError。
举几个小栗子。
以下代码将列表r中的元素合并为一个字符串:"一班男看见星光"
r = ['一班','男','看见星光']
"".join(r)
代码中join方法指定间隔符为空值,因此合并后的字符串实际上并不存在间隔符。
以下代码使用间隔符"-"将列表r中的元素合并为:"一班-男-看见星光"。代码中join方法指定了间隔符为小横杠。
r = ['一班','男','看见星光']
"-".join(r)
以下代码列表r中存在非字符串元素,代码运行后join方法会抛出异常。
r = ['一班','男','看见星光',59]
"-".join(r)
如何避免可迭代对象中存在非字符串元素导致join合并失败呢?例如,将以上代码中列表r的元素合并,返回所需结果为:"一班-男-看见星光-59"
 ̄︶ ̄)↗
——这是本期的第1个练习题(
……
本期的案例工作簿中「文件下载见知识星球」有一个名称为'示例1'的工作表,内容如下图所示,其中C~F列为各科成绩,需要在G列查询成绩大于90分的科目名称。
打开VSCode,创建一个代码单元格,输入并运行以下代码,自动打开目标工作簿。
import xlwings as xw # 导入xlwings
app = xw.App(visible=True, add_book=False) # 创建一个Excel实例
path = r"文件全路径" #文件路径
wb = app.books.open(path)
sht = wb.sheets['示例1'] # 选择工作表
新建一个代码单元格,输入并运行以下代码:
arr = sht.range('c1:f1').expand('down').value
aTit,aRes = arr.pop(0),[]
for r in arr:
aRes.append(["-".join([x for x,y in zip(aTit,r) if y>90])])
sht.range('g2').value = aRes
第2行代码声明了两个列表变量,其中aTit内容为列表arr弹出的第1个元素,也就是标题行,aRes是一个空列表,用于保存计算结果。
第3~4行代码遍历列表arr每一行数据(此时arr已经将标题行pop弹掉了,只剩下了数据行)。
其中第3行代码先使用zip函数将标题列表aTit和数据列表r横向合并成可迭代对象: zip(aTit,r)。合并后的元组为4行2列结构:
然后使用列表推导式遍历每行元素,推导式包含了2个循环变量:x和y,x指向标题元素,y指向成绩元素,列表推导式使用if子句筛选成绩大于90的科目名称。
[x for x,y in zip(aTit,r) if y>90]
最后再使用join函数将符合条件的科目合并成一个字符串,追加写入结果列表aRes。
……
2 丨 split()方法
啪!众所周知,天下大势合久必分分久必合,天下兴亡匹夫有责,谈了恋爱就想结婚,结了婚就想离婚……咳,同样的道理,字符串这个家伙,有合也有分。
split() 是最常用的字符串拆分方法,它可以将字符串按照指定的分隔符拆分成多个子字符串,并返回一个列表,基本语法如下:
str.split(sep=None, maxsplit=-1)
str是被拆分的字符串,参数sep指定分隔符,默认为所有的空白字符(空格、制表符、换行符等),参数maxsplit指定最多拆分的次数,默认为 -1,表示不限制拆分次数。
照例举几个简单的小栗子。
以下代码将字符串'看见星光 语文 99'拆成列表['看见星光', '语文', '99'],split方法省略了所有参数,表示按空白字符(空格、制表符、换行符等)应拆尽拆。
'看见星光 语文 99'.split()
以下代码将字符串'看见星光-语文-99'拆成列表['看见星光', '语文', '99'],其中split方法的将分隔符设置为小横杠,第2参数省略,表示应拆尽拆。
'看见星光-语文-99'.split('-')
以下代码将字符串'看见星光-语文-99'拆成列表['看见星光', '语文-99'],其中split方法的将分隔符设置为小横杠,第2参数设置为1,表示只拆首个小横杠。
'看见星光-语文-99'.split('-',1)
……
本期案例工作簿中有一个名称为'示例2'的工作表,内容如下图所示。其中A列是混合数据,需要按分隔符小横杠,拆分成如C:H列所示的表格。
参考代码如下:
sht = wb.sheets['示例2']
lst = sht.range('a1').expand('down').value
aRes = [s.split('-') for s in lst]
sht.range('c1').value = aRes
第1~2行代码读取A列数据,赋值变量lst。第3行代码使用列表推导式遍历列表lst,使用split()方法将元素按小横杠拆分。
打个响指,还是同样的数据源,需要将其转换为一维表的结构,模拟结果如下图C~F列所示。
摊手,这是本期的第2道练习题。
用涂改液擦拭屏幕可以看到参考答案▼
¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
PS:
记得把本章代码实操一遍:打开VSCode→新建文件→设置环境→复制输入代码→运行,有问题随时在VIP会员微信答疑群中提问交流,行动力是最重要的学习能力没有之一。
……
……
sht = wb.sheets['示例2']
lst = sht.range('a1').expand('down').value
aTit = lst.pop(0).split('-')[2:]
aRes = []
for row in lst:
r = row.split('-')
for x,y in zip(aTit,r[2:]): #zip将标题和数据对应
aRes.append(r[:2] + [x,y]) #将班级姓名科目和成绩 写入结果列表
sht.range('c1').value = [['班级','姓名','科目','成绩']] + aRes
代码用了2个for循环语句,第1个for循环遍历每行数据,第2个for循环使用zip函数将科目和成绩横向合并,再将两者逐行取出,和r[:2]的班级、姓名,追加写入结果列表aRes——这里使用的是本节教程案例1的套路。
其中第2个for循环可以压缩成列表推导式。下面这段代码你还需要思考为什么使用的是aRes+=.... 而不是aRes.append()▼
aRes = [] #结果列表
for row in lst:
r = row.split('-') #分割
aRes += [r[:2] + [x,y] for x,y in zip(aTit,r[2:])]
同样的道理,第1个for循环其实也可以压缩成列表推导式:
aRes = [
row.split('-')[:2] + [x, y]
for row in lst
for x, y in zip(aTit, row.split('-')[2:])
]
又或者压缩成如下推导式:
aRes = [
r[:2] + [x, y]
for row in lst
for r in [row.split('-')]
for x, y in zip(aTit, r[2:])
]
……
……
下期再见。