OpenpyxlベースのExcel読み書きツールクラス
22500 ワード
Openpyxlは、Excelを操作するAPIを提供しています.全体的に、速度的にはやや劣っていますが(Excelの大きなファイルをロードする速度は非常に遅く、その中の最大のテーブルを読む必要はありませんが、ロードしない選択はできないようです)、機能はそろっています.この間、Excelの読み書きの仕事をしていたので、openpyxlベースのExcelツールクラスを整理しました.大量の読み書きデータなどの機能を持っています.
私はツール関数をSQL文の分類方法によってDDL(定義文)、DQL(問合せ文)とDML(操作文)の3種類に分けて、関数の目次は以下のようにして、みんなは自分で使うことができます.
このツールクラスは最近更新され続け、来週は主にExcel形式の関数を追加します.
目次
(一)DDL Excel定義関数
1.クラスツールの入力
Excelファイルのロード
指定Excelファイルの指定Sheetのロード
2.整理類ツール
ExcelファイルのSheetを整理し、余分なSheetを削除し、欠落したSheetを新規作成
3.出力類ツール
OpenpyxlのExcelファイルオブジェクトをファイルに書き込む
(二)DQL Excelクエリー関数
1.タイトルクラスツール
Sheetで指定した見出しの列を検索し、列座標を返します.
Sheetで指定した見出しの列のセットを検索し、列座標のセットを返します.
2.Null値チェッククラスツール
セルの内容が空かどうかを判断
行内の空でないすべてのセルの列座標を検索します.
行の中央の列に空の値があるかどうかを判断します.
3.セルの読み込みツール
セルの内容を読み込み、セルが空の場合は指定した値を返します.
セルの内容を読み込み、セル内の値をstr形式に変換
セルの内容を読み込み、セル内の値をfloat形式に変換
4.クラス検索ツール
指定した値のセルを検索し、セルの列座標を返します.
5.クラス読み込みツール
ExcelのSheetのデータ列を一括して読み込む
Excelテーブルで指定した行データの一部を一括して読み込む
Excelテーブルで指定した行データの一部の列を一括して読み込み、リストまたはそのセルの内容を返す
Excelフォーム全体のデータの一括読み込み
Excelフォームの各行の一部の列のデータを一括して読み込む
Excelテーブルの各行の一部の列のデータを一括して読み込み、その中のいずれかの列に基づいてデータを分類します.
Excelテーブルの各行の一部の列のデータを一括して読み込み、その一部の列(1列以上)に基づいてデータを分類します.
(三)DML Excel操作関数
列幅の一括設定
ロット設定行の高さ
1行のデータを一括して書き込む
1列のデータを一括して書き込む
フォームに大量にデータを書き込む(keyは分類、valueはその分類の複数のリストを記録するdictデータ)
フォームへの一括書込み(keyは分類、valueは単一レコードlist、dictデータ)
(一)DDL Excel定義関数
1.クラスツールの入力
Excelファイルのロード
指定Excelファイルの指定Sheetのロード
2.整理類ツール
ExcelファイルのSheetを整理し、余分なSheetを削除し、欠落したSheetを新規作成
3.出力類ツール
OpenpyxlのExcelファイルオブジェクトをファイルに書き込む
(二)DQL Excelクエリー関数
1.タイトルクラスツール
Sheetで指定した見出しの列を検索し、列座標を返します.
Sheetで指定した見出しの列のセットを検索し、列座標のセットを返します.
2.Null値チェッククラスツール
セルの内容が空かどうかを判断
行内の空でないすべてのセルの列座標を検索します.
行の中央の列に空の値があるかどうかを判断します.
3.セルの読み込みツール
セルの内容を読み込み、セルが空の場合は指定した値を返します.
セルの内容を読み込み、セル内の値をstr形式に変換
セルの内容を読み込み、セル内の値をfloat形式に変換
4.クラス検索ツール
指定した値のセルを検索し、セルの列座標を返します.
5.クラス読み込みツール
ExcelのSheetのデータ列を一括して読み込む
Excelテーブルで指定した行データの一部を一括して読み込む
Excelテーブルで指定した行データの一部の列を一括して読み込み、リストまたはそのセルの内容を返す
Excelフォーム全体のデータの一括読み込み
Excelフォームの各行の一部の列のデータを一括して読み込む
Excelテーブルの各行の一部の列のデータを一括して読み込み、その中のいずれかの列に基づいてデータを分類します.
Excelテーブルの各行の一部の列のデータを一括して読み込み、その一部の列(1列以上)に基づいてデータを分類します.
(三)DML Excel操作関数
列幅の一括設定
ロット設定行の高さ
1行のデータを一括して書き込む
1列のデータを一括して書き込む
フォームに大量にデータを書き込む(keyは分類、valueはその分類の複数のリストを記録するdictデータ)
フォームへの一括書込み(keyは分類、valueは単一レコードlist、dictデータ)
私はツール関数をSQL文の分類方法によってDDL(定義文)、DQL(問合せ文)とDML(操作文)の3種類に分けて、関数の目次は以下のようにして、みんなは自分で使うことができます.
このツールクラスは最近更新され続け、来週は主にExcel形式の関数を追加します.
目次
(一)DDL Excel定義関数
1.クラスツールの入力
Excelファイルのロード
指定Excelファイルの指定Sheetのロード
2.整理類ツール
ExcelファイルのSheetを整理し、余分なSheetを削除し、欠落したSheetを新規作成
3.出力類ツール
OpenpyxlのExcelファイルオブジェクトをファイルに書き込む
(二)DQL Excelクエリー関数
1.タイトルクラスツール
Sheetで指定した見出しの列を検索し、列座標を返します.
Sheetで指定した見出しの列のセットを検索し、列座標のセットを返します.
2.Null値チェッククラスツール
セルの内容が空かどうかを判断
行内の空でないすべてのセルの列座標を検索します.
行の中央の列に空の値があるかどうかを判断します.
3.セルの読み込みツール
セルの内容を読み込み、セルが空の場合は指定した値を返します.
セルの内容を読み込み、セル内の値をstr形式に変換
セルの内容を読み込み、セル内の値をfloat形式に変換
4.クラス検索ツール
指定した値のセルを検索し、セルの列座標を返します.
5.クラス読み込みツール
ExcelのSheetのデータ列を一括して読み込む
Excelテーブルで指定した行データの一部を一括して読み込む
Excelテーブルで指定した行データの一部の列を一括して読み込み、リストまたはそのセルの内容を返す
Excelフォーム全体のデータの一括読み込み
Excelフォームの各行の一部の列のデータを一括して読み込む
Excelテーブルの各行の一部の列のデータを一括して読み込み、その中のいずれかの列に基づいてデータを分類します.
Excelテーブルの各行の一部の列のデータを一括して読み込み、その一部の列(1列以上)に基づいてデータを分類します.
(三)DML Excel操作関数
列幅の一括設定
ロット設定行の高さ
1行のデータを一括して書き込む
1列のデータを一括して書き込む
フォームに大量にデータを書き込む(keyは分類、valueはその分類の複数のリストを記録するdictデータ)
フォームへの一括書込み(keyは分類、valueは単一レコードlist、dictデータ)
(一)DDL Excel定義関数
1.クラスツールの入力
Excelファイルのロード
def load(path, read_only=False, data_only=False, must_exist=True):
"""
DDL: Excel
:param path:(str) Excel
:param read_only:(bool) ( False)
:param data_only:(bool) , ( False)
:param must_exist:(bool) Excel / Excel :True= ,False= None( True)
:return:(openpyxl.workbook.workbook.Workbook)Openpyxl Excel
"""
try:
return load_workbook(path, read_only=read_only, data_only=data_only)
except FileNotFoundError or InvalidFileException:
if must_exist:
utils.sys_exit(" Excel Excel (" + path + ")")
指定Excelファイルの指定Sheetのロード
def load_sheet(path, sheet_name, read_only=False, data_only=False, must_exist=True):
"""
DDL: Excel Sheet
:param path:(str) Excel
:param sheet_name:(str) Sheet
:param read_only:(bool) ( False)
:param data_only:(bool) , ( False)
:param must_exist:(bool) Excel Sheet / Excel :True= ,False= None( True)
:return:(openpyxl.worksheet.worksheet.Worksheet)Openpyxl Sheet
"""
excel = load(path, read_only=read_only, data_only=data_only, must_exist=must_exist)
if excel is None:
return None
if sheet_name in excel.sheetnames:
return excel[sheet_name]
else:
if must_exist:
utils.sys_exit(" Excel Sheet(" + path + "," + sheet_name + ")")
2.整理類ツール
ExcelファイルのSheetを整理し、余分なSheetを削除し、欠落したSheetを新規作成
def arrange_sheet(excel, sheet_list):
"""
DDL: Excel Sheet, Sheet, Sheet( )
:param excel:(openpyxl.workbook.workbook.Workbook) Sheet Excel
:param sheet_list:(list) Sheet
:return , [excel]
"""
if sheet_list is not None and sheet_list != []:
for name in sheet_list:
if name not in excel.sheetnames:
excel.create_sheet(name)
delete_list = []
for name in excel.sheetnames:
if name not in sheet_list:
delete_list.append(name)
for name in delete_list:
excel.remove_sheet(excel[name])
3.出力類ツール
OpenpyxlのExcelファイルオブジェクトをファイルに書き込む
def save(excel, path, must_write=True):
"""
DDL: Openpyxl Excel
:param excel:(openpyxl.workbook.workbook.Workbook) Openpyxl Excel
:param path:(str)
:param must_write:(bool) ( ) :True= ,False= False( True)
:return:(bool)
"""
try:
excel.save(path)
return True
except PermissionError:
if must_write:
utils.sys_exit(" , !")
else:
return False
(二)DQL Excelクエリー関数
1.タイトルクラスツール
Sheetで指定した見出しの列を検索し、列座標を返します.
def find_column(sheet, column_title, row_n=1, start_col_n=1, end_col_n=65536, must_exist=True):
"""
DQL: Sheet ,
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param column_title:(str)
:param row_n:(int)
:param start_col_n:(int) ( )
:param end_col_n:(int) ( )
:param must_exist:(bool) :True= ,False= None( True)
:return:(int)Sheet
"""
for j in range(max(1, start_col_n), min(sheet.max_column, end_col_n) + 1):
if sheet.cell(row=row_n, column=j).value == column_title:
return j
if must_exist:
utils.sys_exit(" (" + column_title + ")")
Sheetで指定した見出しの列のセットを検索し、列座標のセットを返します.
def find_some_column(sheet, column_title_list, row_n=1, start_col_n=1, end_col_n=65536, must_exist=True):
"""
DQL: Sheet , (Dict )
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param column_title_list:(str)
:param row_n:(int)
:param start_col_n:(int) ( )
:param end_col_n:(int) ( )
:param must_exist:(bool) :True= ,False= None( True)
:return:(dict)Sheet , : {' ':1, ' ':2}
"""
col_n_list = {}
for column_title in column_title_list:
col_n_list[column_title] = find_column(sheet, column_title, row_n, start_col_n, end_col_n, must_exist)
return col_n_list
2.Null値チェッククラスツール
セルの内容が空かどうかを判断
def is_none(sheet, row, column):
"""
DQL:
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param row:(int)
:param column:(int)
:return:(bool) :True= ,False=
"""
return sheet.cell(row=row, column=column).value is None
行内の空でないすべてのセルの列座標を検索します.
def row_not_none_col_n(sheet, row, start_column=1, end_column=65536):
"""
DQL:
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param row:(int)
:param start_column:(int) ( )
:param end_column:(int) ( )
:return:(list) , : [1,2]
"""
col_n_list = []
for j in range(max(1, start_column), min(sheet.max_column, end_column) + 1):
if not is_none(sheet, row, j):
col_n_list.append(j)
return col_n_list
行の中央の列に空の値があるかどうかを判断します.
def some_cell_is_none(sheet, row, col_n_list):
"""
DQL:
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param row:(int)
:param col_n_list:(dict) ( None)
: find_some_column , : {' ':1, ' ':2}
:return:(bool) :True= ,False=
"""
if col_n_list is None:
return False
for item in col_n_list:
if is_none(sheet, row, col_n_list[item]):
return True
return False
3.セルの読み込みツール
セルの内容を読み込み、セルが空の場合は指定した値を返します.
def cell_value(sheet, row, column, none_value=""):
"""
DQL: ,
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param row:(int)
:param column:(int)
:param none_value:(object)
:return:(object)
"""
if is_none(sheet, row=row, column=column):
return none_value
else:
return sheet.cell(row=row, column=column).value
セルの内容を読み込み、セル内の値をstr形式に変換
def cell_as_int(sheet, row, column):
"""
DQL: , int ( , )
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param row:(int)
:param column:(object)
:return:(int) int
"""
value = sheet.cell(row=row, column=column).value
if value is None:
return 0
if isinstance(value, int):
return value
if isinstance(value, float):
return int(value)
if re.search("[0-9]+", str(value)) is not None:
return int(re.search("[0-9]+", str(value)).group())
return 0
セルの内容を読み込み、セル内の値をfloat形式に変換
def cell_as_float(sheet, row, column):
"""
DQL: , float ( , )
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param row:(int)
:param column:(object)
:return:(float) float
"""
value = sheet.cell(row=row, column=column).value
if value is None:
return float(0)
if isinstance(value, float):
return value
if isinstance(value, int):
return float(value)
if re.search("[0-9]+", str(value)) is not None:
return float(re.search("[0-9]+", str(value)).group())
if re.search("[0-9]+\.[0-9]+", str(value)) is not None:
return float(re.search("[0-9]+", str(value)).group())
return float(0)
4.クラス検索ツール
指定した値のセルを検索し、セルの列座標を返します.
def find_cell(sheet, search_value):
"""
DQL: ,
, ( )
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param search_value:(object)
:return:(int),(int) , None
"""
for i in range(1, sheet.max_row + 1):
for j in range(1, sheet.max_column + 1):
if sheet.cell(row=i, column=j).value is not None and sheet.cell(row=i, column=j).value == search_value:
return i, j
5.クラス読み込みツール
ExcelのSheetのデータ列を一括して読み込む
def column_total_value(sheet, col_n):
"""
DQL: Excel
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param col_n:(int)
:return:(list) ,
"""
if col_n > sheet.max_column:
return None
column_value = []
for i in range(1, sheet.max_row + 1):
column_value.append(cell_value(sheet, row=i, column=col_n))
return column_value
Excelテーブルで指定した行データの一部を一括して読み込む
def row_value_by_cn(sheet, row_n, col_n_list):
"""
DQL: Excel
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param row_n:(int)
:param col_n_list:(dict) , : find_some_column , : {' ':1, ' ':2}
:return:(list) , col_n_list
"""
row_value = []
for item in col_n_list:
row_value.append(cell_value(sheet, row=row_n, column=col_n_list[item]))
return row_value
Excelテーブルで指定した行データの一部の列を一括して読み込み、リストまたはそのセルの内容を返す
def row_any_value_by_cn(sheet, column_title_row, row_n, column_title_list):
"""
DQL: Excel , list
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param column_title_row:(int)
:param row_n:(int)
:param column_title_list:(list)
:return:
, col_n_list , :[ , ,...]
, :(object)
"""
sheet_cn_list = find_some_column(sheet, column_title_list, row_n=column_title_row)
if len(column_title_list) > 1:
return row_value_by_cn(sheet, row_n=row_n, col_n_list=sheet_cn_list)
else:
return cell_value(sheet, row=row_n, column=sheet_cn_list[list(sheet_cn_list.keys())[0]])
Excelフォーム全体のデータの一括読み込み
def get_sheet(sheet, column_title_list, title_rn=1, data_rn=None, classify_column=None, classify_unique=False,
not_none_column=None):
"""
DQL: Excel
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param column_title_list:(list)
:param title_rn:(int)
:param data_rn:(int) ( )
:param classify_column:(list/str/none) ,
:param classify_unique:(bool)
:param not_none_column:(list) ,
:return:(list/dict) Excel , , col_title_list ;
classify_column get_sheet_by_line,get_sheet_in_classify,get_sheet_some_classify
"""
sheet_nn_cn_list = find_some_column(sheet, utils_old.non_null_list(not_none_column), row_n=title_rn)
if data_rn is None:
data_rn = title_rn + 1
if isinstance(classify_column, list) and classify_column != []:
return get_sheet_some_classify(sheet, classify_column, column_title_list, title_rn, data_rn,
classify_unique, sheet_nn_cn_list)
elif isinstance(classify_column, str):
return get_sheet_in_classify(sheet, classify_column, column_title_list, title_rn, data_rn,
classify_unique, sheet_nn_cn_list)
elif classify_column is not None or classify_column == []:
return get_sheet_by_line(sheet, column_title_list, title_rn, data_rn, sheet_nn_cn_list)
Excelフォームの各行の一部の列のデータを一括して読み込む
def get_sheet_by_line(sheet, column_title_list, title_rn=1, data_rn=2, sheet_nn_cn_list=None):
"""
DQL: Excel
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param column_title_list:(list)
:param title_rn:(int) ( 1 )
:param data_rn:(int) ( 2 )
:param sheet_nn_cn_list:(dict) ,
: find_some_column , : {' ':1, ' ':2}
:return:(list) Excel , , col_title_list
, col_n_list , :[[ , ],[ , ]]
, :[ , ]
"""
data_list = []
for i in range(data_rn, sheet.max_row + 1):
if not some_cell_is_none(sheet, i, sheet_nn_cn_list):
data_list.append(row_any_value_by_cn(sheet, title_rn, i, column_title_list))
return data_list
Excelテーブルの各行の一部の列のデータを一括して読み込み、その中のいずれかの列に基づいてデータを分類します.
def get_sheet_in_classify(sheet, classify_column, column_title_list, title_rn=1, data_rn=2,
classify_unique=False, sheet_nn_cn_list=None):
"""
DQL: Excel ,
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param classify_column:(str) , ,
:param column_title_list:(list)
:param title_rn:(int) ( 1 )
:param data_rn:(int) ( 2 )
:param classify_unique:(bool)
:param sheet_nn_cn_list:sheet_nn_cn_list:(dict) ,
: find_some_column , : {' ':1, ' ':2}
:return:(dict) Excel , , col_title_list
, , : {" 1":[ , ]," 2":[ , ]}
, , : {" 1":[[ , ],[ , ]]," 2":[[ , ],[ , ]]}
, , : {" 1": ," 2": }
, , : {" 1":[ , ]," 2":[ , ]}
"""
data_dict = {}
sheet_cn_classify = find_column(sheet, classify_column, row_n=title_rn)
for i in range(data_rn, sheet.max_row + 1):
data_item = row_any_value_by_cn(sheet, title_rn, i, column_title_list)
data_classify = cell_value(sheet, row=i, column=sheet_cn_classify)
if classify_unique and data_classify is not None and not some_cell_is_none(sheet, i, sheet_nn_cn_list):
data_dict[data_classify] = data_item
if not classify_unique and data_classify is not None and not some_cell_is_none(sheet, i, sheet_nn_cn_list):
utils_old.add_dict_to_list(data_dict, data_classify, data_item)
return data_dict
Excelテーブルの各行の一部の列のデータを一括して読み込み、その一部の列(1列以上)に基づいてデータを分類します.
def get_sheet_some_classify(sheet, classify_column, column_title_list, title_rn=1, data_rn=2,
classify_unique=False, sheet_nn_cn_list=None):
"""
DQL: Excel , ( )
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param classify_column:(list) , ,
:param column_title_list:(list)
:param title_rn:(int) ( 1 )
:param data_rn:(int) ( 2 )
:param classify_unique:(bool)
:param sheet_nn_cn_list:sheet_nn_cn_list:(dict) ,
: find_some_column , : {' ':1, ' ':2}
:return:(dict) Excel , , col_title_list
, , , :
{" 1":{" 1":[ , ]," 2":[ , ]}," 2":{" 1":[ , ]," 2":[ , ]}}
, , get_sheet_in_classify
"""
data_dict = {}
sheet_clfy_cn_list = find_some_column(sheet, classify_column, row_n=title_rn)
for i in range(data_rn, sheet.max_row + 1):
if not some_cell_is_none(sheet, i, sheet_clfy_cn_list) and not some_cell_is_none(sheet, i, sheet_nn_cn_list):
data_item = row_any_value_by_cn(sheet, title_rn, i, column_title_list)
data_classify = data_dict
for j in range(len(classify_column) - 1):
classify_name = cell_value(sheet, row=i, column=sheet_clfy_cn_list[classify_column[j]])
if classify_name not in data_classify:
data_classify[classify_name] = {}
data_classify = data_classify[classify_name]
last_classify_name = cell_value(sheet, row=i, column=sheet_clfy_cn_list[
classify_column[len(classify_column) - 1]])
if classify_unique:
data_classify[last_classify_name] = data_item
else:
utils_old.add_dict_to_list(data_dict, data_classify, data_item)
return data_dict
(三)DML Excel操作関数
列幅の一括設定
def set_column_width(sheet, width_list):
"""
DML:
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param width_list:(list) ,
:return: , [sheet]
"""
for i in range(len(width_list)):
sheet.column_dimensions[get_column_letter(i + 1)].width = width_list[i]
ロット設定行の高さ
def set_row_height(sheet, height_list):
"""
DML:
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param height_list:(list) ,
:return: , [sheet]
"""
for i in range(len(height_list)):
sheet.row_dimensions[i + 1].height = height_list[i]
1行のデータを一括して書き込む
def write_row(sheet, row, value_list):
"""
DML:
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param row:(int)
:param value_list:(list/None)
:return: , [sheet]
"""
if value_list is not None:
for i in range(len(value_list)):
sheet.cell(row=row, column=i + 1).value = value_list[i]
1列のデータを一括して書き込む
def write_column(sheet, column, value_list):
"""
DML:
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param column:(int)
:param value_list:(list/None)
:return: , [sheet]
"""
if value_list is not None:
for i in range(len(value_list)):
sheet.cell(row=i + 1, column=column).value = value_list[i]
フォームに大量にデータを書き込む(keyは分類、valueはその分類の複数のリストを記録するdictデータ)
def write_sheet_cls(sheet, title, data, classify_index):
"""
DML: (key ,value list list, dict )
:{" 1":[[ 1, 2],[ 1, 2]]," 2":[[ 1, 2],[ 1, 2]]}
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param title:(list)
:param data:(dict)
:param classify_index: ( 0 )
:return: , [sheet]
"""
write_row(sheet, 1, title)
sheet_rn = 2
for classify in data:
for item in copy.deepcopy(data[classify]):
item.insert(classify_index, classify)
write_row(sheet, sheet_rn, item)
sheet_rn += 1
フォームへの一括書込み(keyは分類、valueは単一レコードlist、dictデータ)
def write_sheet_cls_item(sheet, title, data, classify_index):
"""
DML: (key ,value list, dict )
:{" 1":[ 1, 2]," 2":[ 1, 2]}
:param sheet:(openpyxl.worksheet.worksheet.Worksheet) Sheet
:param title:(list)
:param data:(dict)
:param classify_index: ( 0 )
:return: , [sheet]
"""
write_row(sheet, 1, title)
sheet_rn = 2
for classify in data:
item = copy.deepcopy(data[classify])
item.insert(classify_index, classify)
write_row(sheet, sheet_rn, item)
sheet_rn += 1