如何使用 Python openpyxl 包操作 Excel 区域?openpyxl CellRange 对象介绍
Python openpyxl 包中的 Excel 区域对象 CellRange
Pythonopenpyxl
包中的CellRange
类,属于模块openpyxl.worksheet.cell_range
,表示 Excel 工作表中的区域,可以在移动区域的操作中指定需要移动的区域。openpyxl
包中的MultiCellRange
类,同样属于模块openpyxl.worksheet.cell_range
,可表示 Excel 工作表中的多个区域。
Pythonopenpyxl
包中的MergedCellRange
类,属于模块openpyxl.worksheet.merge
,继承自CellRange
,可用于表示 Excel 工作表中被合并的单元格区域,他拥有本文讲述的CellRange
对象的所有特性。
使用 Python openpyxl 包的 CellRange 对象创建 Excel 区域
你并不需要主动创建openpyxl
包的CellRange
对象,大多数情况下,使用 Excel 区域的地址可以达成相同的目标,比如,在移动某个区域时,将字符串'A1:C3'
作为参数。如果确实需要 Pythonopenpyxl
包的CellRange
类的实例,那么其构造器如下。
CellRange(range_string=None, min_col=None, min_row=None, max_col=None, max_row=None, title=None)
- range_string 参数
range_string
参数为 Excel 区域的地址(表达式),如果该参数被省略或为None
,那么需要提供参数min_col
,min_row
,max_col
,max_row
。- min_col 参数
min_col
参数是一个整数,用于说明 Excel 区域开始于第几列,1
表示第一列。- min_row 参数
min_row
参数是一个整数,用于说明 Excel 区域开始于第几行,1
表示第一行。- max_col 参数
max_col
参数是一个整数,用于说明 Excel 区域结束于第几列,1
表示第一列。- max_row 参数
max_row
参数是一个整数,用于说明 Excel 区域结束于第几行,1
表示第一行。- title 参数
title
参数用于指定 Excel 区域所在的工作表,如果该参数被省略或为None
,那么 Excel 区域属于当前工作表。
Python openpyxl 包的 CellRange 对象的变量
Pythonopenpyxl
包的CellRange
对象拥有变量min_col
,min_row
,max_col
,max_row
,title
,在未作出修改时,他们的值与传递给CellRange
构造器的实参的值相同。
openpyxl 包的 CellRange 对象所表示的 Excel 区域的最大行和最大列不能小于最小行和最小列
无论你是否为 Pythonopenpyxl
包的CellRange
对象指定了参数range_string
,CellRange
对象的max_row
和max_col
变量都不应该小于min_row
和min_col
变量,否则可能会引发异常ValueError: … must be greater than …
。
openpyxl 包的 Worksheet 对象的 move_range 方法将忽略 CellRange 对象的 title 变量
Pythonopenpyxl
包的CellRange
对象的title
变量,会被Worksheet
对象的move_range
方法忽视,这表示通过某个Worksheet
对象来移动另一个 Excel 工作表中的区域是不可行的。
Excel 文件Data.xlsx
包含了两个工作表Fruit
和Trees
,虽然在创建CellRange
对象时,我们指定了参数title
,但move_range
方法并不会移动工作表Trees
中的区域。
# 读取 Excel 文件 Data.xlsx 中的工作表 Fruit
from openpyxl import load_workbook
wb = load_workbook('Data.xlsx')
ws = wb['Fruit']
from openpyxl.worksheet.cell_range import CellRange
# 创建区域 Trees!A1:B2,其中 Trees 不会发挥作用
range = CellRange(min_col=1, min_row=1, max_col=2, max_row=2, title='Trees')
# 移动工作表 Fruit 的区域 A1:B2,而不是工作表 Trees
ws.move_range(range, 1, 1)
wb.save('Move.xlsx')
获取 Python openpyxl 包的 CellRange 对象所表示的 Excel 区域的边界和地址
Pythonopenpyxl
包的CellRange
对象的bounds
属性,可以获取CellRange
对象所表示的 Excel 区域的边界,其返回值是一个依次包含变量min_col
,min_row
,max_col
和max_row
的 Python 元组,即区域的最小列,最小行,最大列,最大行。
Pythonopenpyxl
包的CellRange
对象的top
,bottom
,left
,right
属性,可以获取CellRange
对象所表示的 Excel 区域的最上方的一行,最下方的一行,最左边的一列,最右边的一列的单元格的位置信息。他们的返回值是一个 Python 列表,列表中包含了一系列格式为(x,y)
的元组,其中x
表示单元格位于哪一行,y
表示单元格位于哪一列。
cellrange.bounds
cellrange.top
cellrange.bottom
cellrange.left
cellrange.right
Pythonopenpyxl
包的CellRange
对象的coord
属性,可以获取CellRange
对象所表示的 Excel 区域的地址(比如,A1:C3
),该地址不包含title
变量所表示的 Excel 工作表名称。
cellrange.coord
from openpyxl.worksheet.cell_range import CellRange
# 创建区域 B2:D4
range = CellRange('B2:D4')
# 显示区域的边界
print(range.bounds)
print(f'最上方一行的单元格的位置信息 {range.top}')
print(f'最下方一行的单元格的位置信息 {range.bottom}')
print(f'最左边一行的单元格的位置信息 {range.left}')
print(f'最右边一行的单元格的位置信息 {range.right}')
# 创建区域 C2:J4,工作表名称为 SheetA
range = CellRange(min_col=3, min_row=2, max_col=10, max_row=4, title='SheetA')
# 显示区域的地址
print(range.coord)
(2, 2, 4, 4)
最上方一行的单元格的位置信息 [(2, 2), (2, 3), (2, 4)]
最下方一行的单元格的位置信息 [(4, 2), (4, 3), (4, 4)]
最左边一行的单元格的位置信息 [(2, 2), (3, 2), (4, 2)]
最右边一行的单元格的位置信息 [(2, 4), (3, 4), (4, 4)]
C2:J4
获取和设置 Python openpyxl 包的 CellRange 对象所表示的 Excel 区域的大小
你可以简单的通过CellRange
对象的变量min_col
,min_row
,max_col
,max_row
,来获取或设置CellRange
对象所表示的 Excel 区域的大小,不过,CellRange
的以下特性可实现相同的效果。
Pythonopenpyxl
包的CellRange
对象的size
属性,可以获取CellRange
对象所表示的 Excel 区域的大小(区域包含的行和列的个数),其返回值是一个格式为{'columns':cs,'rows':rs}
的 Python 字典对象,其中cs
为 Excel 区域包含的列的数量,rs
为 Excel 区域包含的行的数量。
cellrange.size
Pythonopenpyxl
包的CellRange
对象的expand
和shrink
方法,可用于改变CellRange
对象所表示的 Excel 区域的大小,其中expand
方法可以扩展 Excel 区域,shrink
方法可以缩小 Excel 区域。
cellrange.expand(right=0, down=0, left=0, up=0)
cellrange.shrink(right=0, bottom=0, left=0, top=0)
- right 参数
right
参数为 Excel 区域最右边一列向外或向内移动的列数,设置为负数表示反向操作。- down,bottom 参数
down
或bottom
参数为 Excel 区域最下方一行向外或向内移动的行数,设置为负数表示反向操作。- left 参数
left
参数为 Excel 区域最左边一列向外或向内移动的列数,设置为负数表示反向操作。- up,top 参数
up
或top
参数为 Excel 区域最上方一行向外或向内移动的行数,设置为负数表示反向操作。
from openpyxl.worksheet.cell_range import CellRange
# 创建区域 B2:D4
range = CellRange('B2:D4')
# 显示区域大小
print(range.size)
# 最右边列向内移动 1 列,最下边行向外移动 1 行,最左边列向外移动 1 列,最上边行向内移动 1 行
range.expand(-1, 1, 1, -1)
print(range.coord)
# 最右边列向外移动 1 列,最下边行向内移动 1 行,最左边列向内移动 1 列,最上边行向外移动 1 行
range.shrink(-1, 1, 1, -1)
print(range.coord)
{'columns': 3, 'rows': 3}
A3:C5
B2:D4
遍历 Python openpyxl 包的 CellRange 对象所表示的 Excel 区域中的单元格
当然,要遍历 Excel 工作表中的单元格,最好最简便的方法是使用openpyxl
包的Worksheet
对象的[]
运算符,不过,你依然可以借助 Pythonopenpyxl
包的CellRange
对象的rows
,cols
或cells
属性来完成相同的任务。
不同于Worksheet
对象的[]
运算符,CellRange
对象的rows
,cols
属性返回的是一个可按照行或列遍历单元格位置的 Python 生成器对象,每一行或每一列将作为一个 Python 列表存在,每个列表都包含一系列格式为(x,y)
的元组,其中x
表示单元格位于哪一行,y
表示单元格位于哪一列。
openpyxl
包的CellRange
对象的cells
属性的返回值是一个itertools.product
对象,该对象包含了 Excel 区域内所有单元格的位置信息,这些位置信息的顺序与rows
属性相同,只不过他们不再按照行来进行划分(每一行作为一个 Python 列表)。
cellrange.rows
cellrange.cols
cellrange.cells
工作表
关于如何获取 Excel 单元格,你可以查看使用 Python openpyxl 包的 Worksheet 对象获取 Excel 单元格一段。
在下面的代码中,我们通过CellRange
对象的rows
和cells
属性遍历了区域内的 Excel 单元格,其中cells
不需要再次使用for
语句。
# 读取 Excel 文件 Data.xlsx 中的工作表 Trees
from openpyxl import load_workbook
wb = load_workbook('Data.xlsx')
ws = wb['Trees']
from openpyxl.worksheet.cell_range import CellRange
# 创建区域 A1:B2
range = CellRange('A1:B2')
# 借助 CellRange 的 row 属性遍历单元格
for row in range.rows:
# x 和 y 分别表示单元格位于哪一行和哪一列
for x, y in row:
c = ws.cell(x, y)
print(f'{c.coordinate}={c.value}')
# 借助 CellRange 的 cells 属性遍历单元格
for x, y in range.cells:
c = ws.cell(x, y)
print(f'({x}, {y})={c.value}')
A1=苹果树
B1=10
A2=梨树
B2=20
(1, 1)=苹果树
(1, 2)=10
(2, 1)=梨树
(2, 2)=20
移动 Python openpyxl 包的 CellRange 对象所表示的 Excel 区域的位置
Pythonopenpyxl
包的CellRange
对象的shift
方法,可用于移动CellRange
对象所表示的 Excel 区域。
cellrange.shift(col_shift=0, row_shift=0)
- col_shift 参数
col_shift
参数为 Excel 区域移动的列数,1
表示向右移动一列,-1
表示向左移动一列。- row_shift 参数
row_shift
参数为 Excel 区域移动的行数,1
表示向下移动一行,-1
表示向上移动一行。
不能将 openpyxl 包的 CellRange 对象所表示的 Excel 区域移动到工作表之外
如果给出的col_shift
或row_shift
参数会导致CellRange
对象所表示的 Excel 区域被移动到工作表之外,那么shift
方法将引发异常ValueError: Invalid shift value: col_shift=…, row_shift=…
,Excel 区域不会被移动。
Python openpyxl 包的 CellRange 对象的 shift 方法不会移动 Excel 区域内的单元格
很明显的,CellRange
对象的shift
方法不会移动 Excel 区域内的单元格,他只是改变了区域的位置,如果你希望移动单元格,那么可以使用Worksheet
对象的move_range
方法。
工作表
关于如何移动 Excel 单元格,你可以查看使用 Python openpyxl 包的 Worksheet 对象移动 Excel 单元格一段。
在下面的代码中,第一次调用shift
方法,区域B2:D4
被移动至C3:E5
,第二次调用shift
方法,区域C3:E5
会被移动到工作表之外,因此引发了异常。
from openpyxl.worksheet.cell_range import CellRange
# 创建区域 B2:D4
range = CellRange('B2:D4')
# 向右下方移动区域
range.shift(1, 1)
print(range.coord)
# ERROR 移动后区域将超出工作表的范围
range.shift(row_shift=-3)
C3:E5
…
ValueError: Invalid shift value: col_shift=0, row_shift=-3
判断 Python openpyxl 包的 CellRange 对象所表示的 Excel 区域之间的关系
Pythonopenpyxl
包的CellRange
对象的isdisjoint
方法,可用于判断CellRange
对象所表示的 Excel 区域与其他 Excel 区域的交集是否为空,即是否两个 Excel 区域没有相同地址的单元格。
Pythonopenpyxl
包的CellRange
对象的issubset
方法,可用于判断CellRange
对象所表示的 Excel 区域是否为其他 Excel 区域的子集,即是否等于或包含在其他 Excel 区域中。
Pythonopenpyxl
包的CellRange
对象的issuperset
方法,可用于判断CellRange
对象所表示的 Excel 区域是否为其他 Excel 区域的超集,即是否等于或包含了其他 Excel 区域。
cellrange.isdisjoint(other)
cellrange.issubset(other)
cellrange.issuperset(other)
- other 参数
other
参数为参与关系判断的其他 Excel 区域对应的CellRange
对象。如果other
对应的CellRange
对象拥有有效的title
变量,并且其值与原区域对应的CellRange
对象的title
变量的值不同,那么将引发异常ValueError: Cannot work with ranges from different worksheets
。
在下面的示例中,区域B2:D4
是区域B2:D4
的子集和超集,因为两个区域相同。
from openpyxl.worksheet.cell_range import CellRange
# 创建区域 B2:D4,然后判断他与其他区域的关系
range = CellRange('B2:D4')
print(f'B2:D4 与 A1:B2 的交集为空?{range.isdisjoint(CellRange("A1:B2"))}')
print(f'B2:D4 与 F4:H5 的交集为空?{range.isdisjoint(CellRange("F4:H5"))}')
print(f'B2:D4 是否为 A1:D4 的子集?{range.issubset(CellRange("A1:D4"))}')
print(f'B2:D4 是否为 B2:D4 的子集?{range.issubset(CellRange("B2:D4"))}')
print(f'B2:D4 是否为 C3:C3 的超集?{range.issuperset(CellRange("C3:C3"))}')
print(f'B2:D4 是否为 B2:D4 的超集?{range.issuperset(CellRange("B2:D4"))}')
B2:D4 与 A1:B2 的交集为空?False
B2:D4 与 F4:H5 的交集为空?True
B2:D4 是否为 A1:D4 的子集?True
B2:D4 是否为 B2:D4 的子集?True
B2:D4 是否为 A1:D4 的超集?True
B2:D4 是否为 C3:C3 的超集?True
计算 Python openpyxl 包的 CellRange 对象所表示的 Excel 区域
Pythonopenpyxl
包的CellRange
对象的intersection
方法,可用于计算并返回一个新的CellRange
对象,该对象表示的 Excel 区域为原区域与目标区域的交集。如果原区域与目标区域的交集为空,那么将引发异常ValueError: Range … doesn't intersect …
。
Pythonopenpyxl
包的CellRange
对象的union
方法,可用于计算并返回一个新的CellRange
对象(其title
变量的值与原CellRange
对象的title
变量的值相同),该对象表示的 Excel 区域为原区域与目标区域的并集。
cellrange.intersection(other)
cellrange.union(other)
- other 参数
other
参数为参与计算的目标 Excel 区域对应的CellRange
对象。对于union
方法,如果other
对应的CellRange
对象拥有有效的title
变量,并且其值与原区域对应的CellRange
对象的title
变量的值不同,那么将引发异常ValueError: Cannot work with ranges from different worksheets
。
from openpyxl.worksheet.cell_range import CellRange
# 创建区域 B2:D4,然后与其他区域进行计算
range = CellRange('B2:D4')
print(f'B2:D4 与 A1:B2 的交集:{range.intersection(CellRange("A1:B2"))}')
print(f'B2:D4 与 A1:D4 的并集:{range.union(CellRange("A1:D4"))}')
print(f'B2:D4 与 A1:A1 的并集:{range.union(CellRange("A1:A1"))}')
try:
# ERROR 两个区域没有交集
range.intersection(CellRange('A1:A1'))
except Exception as err:
print(err)
try:
# ERROR 目标区域的 title 有效并且与原区域不同
range.union(CellRange('A1:A1', title='Other'))
except Exception as err:
print(err)
B2:D4 与 A1:B2 的交集:B2
B2:D4 与 A1:D4 的并集:A1:D4
B2:D4 与 A1:A1 的并集:A1:D4
# 下面的第二个 B2:D4 应该是 A1:A1,这可能是 openpyxl 的一个 BUG
Range B2:D4 doesn't intersect B2:D4
Cannot work with ranges from different worksheets