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ファイルのロード
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