エクセルを処理する時、xlrdはよく使っている。ところが、通常のsheet.cell(0,0).valueだと、結合したセルの値は空になる。実は、sheetクラスに、merged_cellsというものがあり、そこから実際の値を取れる。

import xlrd
excel_path = "test.xlsx"
wb = xlrd.open_workbook(excel_path)
sh = wb.sheet_by_name("Sheet1")
print("通常のやりかた")
print("A1: ", sh.cell(0, 0).value)  # A1-B5
print("A3: ", sh.cell(2, 0).value)  # ""(空)
print("B5: ", sh.cell(4, 1).value)  # ""(空)
print("D9: ", sh.cell(8, 3).value)  # ""(空)
print("H7: ", sh.cell(6, 7).value)  # ""(空)
for crange in sh.merged_cells:
    # crange: row_top, row_length, col_top, col_length
    print("crange: ", crange)
    """
    crange:  (0, 5, 0, 2)
    crange:  (3, 9, 3, 4)
    crange:  (6, 7, 5, 8)
    """

merged_cellsから、sheet内結合した全てのセル範囲がわかる。crange:(開始行, 結合した行数, 開始列, 結合した列数)

これを元に、該当セルの行列がある範囲内にある場合、そのセルが別のセルと結合しているということになる。なお、結合範囲内のセルの値は、一番左上のセルに保存されている。

def get_cell_real_value(sh, row, col):
    cell = sh.cell(row, col)
    for crange in sh.merged_cells:  # 結合したセル
        if crange[0] <= row < crange[1] and crange[2] <= col < crange[3]:
            # 結合範囲内のセルの場合
            # 結合したセルの値は、一番左上のセルに保存されている
            return sh.cell(crange[0], crange[2]).value
    return cell.value

実際の結果:

print("-" * 50)
print("A1: ", get_cell_real_value(sh, 0, 0))  # A1-B5
print("A3: ", get_cell_real_value(sh, 2, 0))  # A1-B5
print("B5: ", get_cell_real_value(sh, 4, 1))  # A1-B5
print("-" * 50)
print("D4: ", get_cell_real_value(sh, 3, 3))  # D4-D9
print("D9: ", get_cell_real_value(sh, 8, 3))  # D4-D9
print("-" * 50)
print("F7: ", get_cell_real_value(sh, 6, 5))  # F7-H7
print("H7: ", get_cell_real_value(sh, 6, 7))  # F7-H7