URLhttps://learnscript.net/zh/office-programming/openpyxl/ranges/
    复制链接转到说明  示例

    如何使用 openpyxl 处理 Excel 区域?CellRange 对象介绍

    我被代码海扁署名-非商业-禁演绎
    阅读 17:17·字数 5187·更新 

    openpyxl Excel 区域对象 CellRange

    openpyxl包中的CellRange类,属于模块openpyxl.worksheet.cell_range,表示 Excel 工作表中的区域,可以在移动区域的操作中指定需要移动的区域。openpyxl包中的MultiCellRange类,同样属于模块openpyxl.worksheet.cell_range,可表示 Excel 工作表中的多个区域。

    openpyxl包中的MergedCellRange类,属于模块openpyxl.worksheet.merge,继承自CellRange,可用于表示 Excel 工作表中被合并的单元格区域,他拥有本文讲述的CellRange对象的所有特性。

    创建 Excel 区域

    你并不需要主动创建CellRange对象,大多数情况下,使用 Excel 区域的地址可以达成相同的目标,比如,在移动某个区域时,将字符串'A1:C3'作为参数。如果确实需要CellRange类的实例,那么其构造器如下。

    CellRange(range_string=None, min_col=None, min_row=None, max_col=None, max_row=None, title=None)

    range_string 参数

    range_string参数为区域的地址(表达式),如果该参数被省略或为None,那么需要提供参数min_colmin_rowmax_colmax_row

    min_col 参数

    min_col参数是一个整数,用于说明区域开始于第几列,1表示第一列。

    min_row 参数

    min_row参数是一个整数,用于说明区域开始于第几行,1表示第一行。

    max_col 参数

    max_col参数是一个整数,用于说明区域结束于第几列,1表示第一列。

    max_row 参数

    max_row参数是一个整数,用于说明区域结束于第几行,1表示第一行。

    title 参数

    title参数用于指定区域所在的工作表,如果该参数被省略或为None,那么区域属于当前工作表。

    CellRange 对象的变量

    CellRange对象拥有变量min_colmin_rowmax_colmax_rowtitle,在未作出修改时,他们的值与传递给CellRange构造器的实参的值相同。

    CellRange 对象所表示的区域的最大行和最大列不能小于最小行和最小列

    无论你是否为CellRange对象指定了参数range_stringCellRange对象的max_rowmax_col变量都不应该小于min_rowmin_col变量,否则可能会引发异常ValueError: … must be greater than …

    Worksheet 对象的 move_range 方法将忽略 CellRange 对象的 title 变量

    CellRange对象的title变量,会被Worksheet对象的move_range方法忽视,这表示通过某个Worksheet对象来移动另一个工作表中的区域是不可行的。

    Excel 文件Data.xlsx包含了两个工作表FruitTrees,虽然在创建CellRange对象时,我们指定了参数title,但move_range方法并不会移动工作表Trees中的区域。

    move.py
    # 读取 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')

    获取 Excel 区域的边界和地址

    CellRange对象的bounds属性,可以获取CellRange对象所表示的 Excel 区域的边界,其返回值是一个依次包含变量min_colmin_rowmax_colmax_row的 Python 元组,即区域的最小列,最小行,最大列,最大行。

    CellRange对象的topbottomleftright属性,可以获取CellRange对象所表示的 Excel 区域的最上方的一行,最下方的一行,最左边的一列,最右边的一列的单元格的位置信息。他们的返回值是一个 Python 列表,列表中包含了一系列格式为(x,y)的元组,其中x表示单元格位于哪一行,y表示单元格位于哪一列。

    cellrange.bounds
    cellrange.top
    cellrange.bottom
    cellrange.left
    cellrange.right

    CellRange对象的coord属性,可以获取CellRange对象所表示的 Excel 区域的地址(比如,A1:C3),该地址不包含title变量所表示的工作表名称。

    cellrange.coord

    range.py
    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

    获取和设置 Excel 区域的大小

    你可以简单的通过CellRange对象的变量min_colmin_rowmax_colmax_row,来获取或设置CellRange对象所表示的 Excel 区域的大小,不过,CellRange的以下特性可实现相同的效果。

    CellRange对象的size属性,可以获取CellRange对象所表示的 Excel 区域的大小(区域包含的行和列的个数),其返回值是一个格式为{'columns':cs,'rows':rs}的 Python 字典对象,其中cs为区域包含的列的数量,rs为区域包含的行的数量。

    cellrange.size

    CellRange对象的expandshrink方法,可用于改变CellRange对象所表示的 Excel 区域的大小,其中expand方法可以扩展区域,shrink方法可以缩小区域。

    cellrange.expand(right=0, down=0, left=0, up=0)
    cellrange.shrink(right=0, bottom=0, left=0, top=0)

    right 参数

    right参数为区域最右边一列向外或向内移动的列数,设置为负数表示反向操作。

    down,bottom 参数

    downbottom参数为区域最下方一行向外或向内移动的行数,设置为负数表示反向操作。

    left 参数

    left参数为区域最左边一列向外或向内移动的列数,设置为负数表示反向操作。

    up,top 参数

    uptop参数为区域最上方一行向外或向内移动的行数,设置为负数表示反向操作。

    size.py
    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

    遍历 Excel 区域中的单元格

    当然,要遍历 Excel 工作表中的单元格,最好最简便的方法是使用Worksheet对象的[]运算符,不过,你依然可以借助CellRange对象的rowscolscells属性来完成相同的任务。

    不同于Worksheet对象的[]运算符,CellRange对象的rowscols属性返回的是一个可按照行或列遍历单元格位置的 Python 生成器对象,每一行或每一列将作为一个 Python 列表存在,每个列表都包含一系列格式为(x,y)的元组,其中x表示单元格位于哪一行,y表示单元格位于哪一列。

    CellRange对象的cells属性的返回值是一个itertools.product对象,该对象包含了 Excel 区域内所有单元格的位置信息,这些位置信息的顺序与rows属性相同,只不过他们不再按照行来进行划分(每一行作为一个 Python 列表)。

    cellrange.rows
    cellrange.cols
    cellrange.cells

    工作表

    关于如何获取 Excel 单元格,你可以查看获取 Excel 单元格一段。

    在下面的代码中,我们通过CellRange对象的rowscells属性遍历了区域内的单元格,其中cells不需要再次使用for语句。

    iterate.py
    # 读取 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

    移动 Excel 区域的位置

    CellRange对象的shift方法,可用于移动CellRange对象所表示的 Excel 区域。

    cellrange.shift(col_shift=0, row_shift=0)

    col_shift 参数

    col_shift参数为区域移动的列数,1表示向右移动一列,-1表示向左移动一列。

    row_shift 参数

    row_shift参数为区域移动的行数,1表示向下移动一行,-1表示向上移动一行。

    不能将 CellRange 对象所表示的区域移动到工作表之外

    如果给出的col_shiftrow_shift参数会导致CellRange对象所表示的区域被移动到工作表之外,那么shift方法将引发异常ValueError: Invalid shift value: col_shift=…, row_shift=…,区域不会被移动。

    CellRange 对象的 shift 方法不会移动区域内的单元格

    很明显的,CellRange对象的shift方法不会移动区域内的单元格,他只是改变了区域的位置,如果你希望移动单元格,那么可以使用Worksheet对象的move_range方法。

    工作表

    关于如何移动 Excel 单元格,你可以查看移动 Excel 单元格一段。

    在下面的代码中,第一次调用shift方法,区域B2:D4被移动至C3:E5,第二次调用shift方法,区域C3:E5会被移动到工作表之外,因此引发了异常。

    shift.py
    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

    判断 Excel 区域之间的关系

    CellRange对象的isdisjoint方法,可用于判断CellRange对象所表示的 Excel 区域与其他区域的交集是否为空,即是否两个区域没有相同地址的单元格。

    CellRange对象的issubset方法,可用于判断CellRange对象所表示的 Excel 区域是否为其他区域的子集,即是否等于或包含在其他区域中。

    CellRange对象的issuperset方法,可用于判断CellRange对象所表示的 Excel 区域是否为其他区域的超集,即是否等于或包含了其他区域。

    cellrange.isdisjoint(other)
    cellrange.issubset(other)
    cellrange.issuperset(other)

    other 参数

    other参数为参与关系判断的其他区域对应的CellRange对象。如果other对应的CellRange对象拥有有效的title变量,并且其值与原区域对应的CellRange对象的title变量的值不同,那么将引发异常ValueError: Cannot work with ranges from different worksheets

    在下面的示例中,区域B2:D4是区域B2:D4的子集和超集,因为两个区域相同。

    relationship.py
    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

    计算 Excel 区域

    CellRange对象的intersection方法,可用于计算并返回一个新的CellRange对象,该对象表示的 Excel 区域为原区域与目标区域的交集。如果原区域与目标区域的交集为空,那么将引发异常ValueError: Range … doesn't intersect …

    CellRange对象的union方法,可用于计算并返回一个新的CellRange对象(其title变量的值与原CellRange对象的title变量的值相同),该对象表示的 Excel 区域为原区域与目标区域的并集。

    cellrange.intersection(other)
    cellrange.union(other)

    other 参数

    other参数为参与计算的目标区域对应的CellRange对象。对于union方法,如果other对应的CellRange对象拥有有效的title变量,并且其值与原区域对应的CellRange对象的title变量的值不同,那么将引发异常ValueError: Cannot work with ranges from different worksheets

    calculate.py
    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

    源码

    src/zh/openpyxl/ranges·codebeatme/office-programming·GitHub