0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CSVファイルの結合ツール作成 #Python

Last updated at Posted at 2025-10-18

挨拶

今回もPythonの学習を進めていきます。今回作るのはCSVファイルの結合ツールを作成していきます。
前回記事:クリップボード履歴管理ツール

実行環境

  • OS : Pop!_OS
  • Anaconda

教本

今回の目標

今回の最終目標は複数のCSVファイルを選択し、結合してテーブルに表示するツールの作成です。

CSVファイルについて

まずは、今回の学習に当たってCSVファイルについての概要を確認します。
CSVファイルとは

  • 多くの場合、CSVの1行目は"ヘッダー(項目名)" である。しかし、中には1行目がヘッダーでは無いCSVファイルもあるため確認が必要
  • ヘッダーがある場合、2行目以降のカンマ( , )で区切られた部分が "フィールド(データ値)"と呼ばれる
  • CSVの行は1行が"1件のデータ(レコード)" を表し、複数のフィールドを持つ

CSV例

果物,産地,価格 
りんご,青森,"300"
桃,山梨,"600"

Pythonには、CSVファイルを読み書きするライブラリがありますが、今回は標準ライブラリのcsvモジュールを使います。

CSVファイルへの読み込みと書き込み

まずはツール作成前に、PythonでCSVファイルの読み込みと書き込みをする方法を確認します。細かい処理の内容については、コード内のコメントを参考にしてください。

CSVファイルの作成

まずは、読み込むためのCSVファイルを作成します。
今回は、新しいファイルを作成後し、前述のCSV例をコピペして、CSVファイルとして保存しました。このファイルを使い、読み込みと書き込みの確認を行います。

作成したCSVファイルを読み込む

ここから、CSVファイルをCSVモジュールなしで読み込むコードを書いていきます。

CSVファイル読み込みコード(CSVモジュールなし)
# 1.CSVデータをテキストとして読み込みカンマで区切る  - 不完全な方法
result = [] # 読み込んだデータを格納する配列resultを作成
with open("test.csv","r",encoding= "utf-8") as fp: # CSVファイルをテキストとして読み込み
    for line in fp.readlines():  # ファイルの各行を順番に読み込み
        row = line.split(",") # カンマで区切り配列rowに格納
        result.append(row) # 配列resultにrowを追加
# データが正しく読み込めたか確認
peach = result[2] # CSVファイル3行目のデータを取得
print(f"(1) 果物: {peach[0] } 価格: {peach[2]}")  # index0:果物名とindex2:価格を表示
結果:# 結果:(1) 果物: 桃 価格: "600"

コメントに"不完全な方法"と書いた理由は、この方法だと、データ内にダブルクオートが含まれていた場合、ダブルクオートも一緒に出力されてしまいます。 ダブルクオートは本来、囲んだ部分を文字列として認識させるためにあり、表示されるのは望ましくありません。

また、CSVのデータにカンマが含まれていた場合、その部分で区切りを付けてしまうため正しく表示できません。

データにカンマが含まれていた場合の表示:# 結果:(1) 果物: 桃 価格: "6,
CSVファイル読み込みコード(モジュールあり)

今度は、標準ライブラリのCSVモジュールを使い、同じ処理のコードを書いていきます。

# 2.CSVモジュールを使いCSVを読み込む
import csv # CSVモジュールをインポート
result = [] # 読み込んだデータを格納する配列resultを作成
with open("test.csv","r",encoding= "utf-8") as fp: # CSVファイルをテキストとして読み込み
    csv_reader = csv.reader(fp) # CSVモジュールの"reader"を使ったオブジェクトを作成
    for row in csv_reader:
        result.append(row)
# データが正しく読み込めたか確認
peach = result[2] # CSVファイル3行目のデータを取得
print(f"(1) 果物: {peach[0] } 価格: {peach[2]}")  # index0:果物名とindex2:価格を表示
#結果:(2) 果物: 桃 価格: 600

1と2のコードで使ったCSVデータは同じものを使用していますが、1では価格の表示が"600"となっていたのに対し、2ではダブルクオートが抜かれ、600と表示されています。CSVモジュールを使うことで、望ましい結果で出力できました。

CSVファイルに書き込む

今度は、PythonからCSVファイルを作成しデータを書き込むコードを書いていきます。

import csv
# リスト型のデータを作成。この値がCSVファイルに書き込まれる
data = [
        ["ABC,Inc", 500000,4 ],
        ["WXZT,LLC",800000,4]
        ]
# CSV形式のファイルを作成し書き込む
with open("company.csv","w",encoding="utf-8") as f:
    writer = csv.writer(f) # CSVファイルの書き込みオブジェクトを作成
    writer.writerows(data) # 作成したファイルにdataのデータを全て格納

作成したCSVの中身:

ABC,Inc	500000	4
WXZT,LLC	800000	4
Excelとの互換について

CSVファイルをExcelで開く際に起こる文字化けですが、文字エンコードの違いが原因となることが多いです。
しかし、私の環境にExcelを導入していないため検証できないこと、学習の目的が"CSVファイルの結合ツール作成"であることから、今回は説明を省きます。

CSVファイルを読み込んでダイアログ表示させる

先程作成したCSVファイルを読み込んで、ファイルを選択したこと、保存したことを表示するダイアログを表示させるコードを書いていきます。

# ダイアログを画面に表示させるコード
import TkEasyGUI as sg 

# ファイル選択のダイアログを表示
file = sg.popup_get_file(
    "CSVファイルを選択してください。",
    multiple_files= False, # 単一のファイルの場合はFalseを指定
    file_types=("CSVファイル","*.csv")
    )
sg.popup(file,"*.csv") # 選択したファイルの絶対パスを表示

# ファイル保存のダイアログ
file = sg.popup_get_file(
    "保存するCSVファイルを選択してください",
    save_as=True,
    file_types=(("CSVファイル",".*csv"),) 
    )
sg.popup(file,title="保存したファイル名")

このコードではダイアログの表示しか行えないため、ファイルの保存はできません。このコードをベースに、複数のファイルを選択して結合するツールを作成していきます。

複数のCSVファイルを選択して結合するツール

このツールでできることは、

  1. 複数のCSVファイルを選択
  2. 選択したファイルを結合してテーブル形式で表示
  3. 「保存」ボタンを押すことで結合したCSVデータをファイルに保存

GUIには、前回同様に"TkEasyGUI"を使用します。

# ファイル結合するツール
import csv 
import TkEasyGUI as sg

# ツールの基本動作を定義するmain関数を作成
def main():
    while True:
        file = sg.popup_get_file(
            "CSVファイルを選択してください",
            multiple_files=True, # 複数選択したいときはTrueを指定
            file_types=(("CSV","*.csv"),)
            )
        if len(file) ==0 or file == "": #選択したCSVファイルが存在しない場合は処理を中止
            break
        all_datas = []
        for filenames in file: #選択したファイルを変数に格納
            data = read_csv(filenames) #read_csv関数を使いcsvファイルを読み込む
            if data is None:
                sg.popup_error(filenames + "ファイルが読み込めません")
                continue
            # ヘッダーが重複する場合1つに統一
            if len(all_datas) >= 2 and len(data) >=2:
                if all_datas[0] == data[0]:
                    data = data[1:]
            all_datas += data
        if show_csv(all_datas) == False: # show_csv関数を使いテーブル表示する
            break
        
#read_csv関数を作成
def read_csv(filenames):
    try:
        with open(filenames,"r",encoding="utf-8") as f:
            reader =  csv.reader(f)
            data = [row for row in reader] #ファイルの内容を1行ずつ読み配列dataに格納
        return data
    except:
        pass
    return None #読み込みに市パイした場合は何も返さない

#CSVをテーブル表示するshow_csv関数を作成
def show_csv(data):
    if len(data) == 0: # 中身がない場合は空と表示する
        data = [[""],[""]]
    #表示するレイアウトを指定
    layout = [
        [sg.Table(
            key="-data-",
            values=data[1:],#データ(フィールド)を指定
            headings=data[0], # ヘッダー部分を指定
            expand_x=True,expand_y=True ,#テーブルの表示幅をウィンドウの大きさに合わせる
            justification="left" ,# 左詰めで表示
            auto_size_columns=True, #データに合わせてカラムの大きさを変える
            max_col_width=30, #カラムの最大値を指定
            font=("Aria",14))],
        [sg.Button("ファイルを選択"),sg.Button("保存"),sg.Button("終了")]
        ]
    # ウィンドウを作成
    window = sg.Window("CSV結合ツール",layout,size=(500,300),resizable=True)
    #イベントごとの処理
    flag = False
    while True:
        event,_ = window.read()
        if event in [sg.WINDOW_CLOSED,"終了"]:
            break
        #ファイル選択を選んだ場合フラグを変更
        if event == "ファイルを選択":
            flag = True
            break
        #ファイルの保存を選択した場合CSVファイルに書き込む
        if event == "保存":
            filenames = sg.popup_get_file(
                "保存するファイルを選択",
                save_as=True,
                file_types=(("CSV","*.csv"),)
                )
            if filenames == "" or filenames is None:
                continue
            with open(filenames,"w",encoding="utf-8",newline="") as f:
                writer = csv.writer(f)
                writer.writerows(data)
    window.close()
    return flag
if  __name__ == "__main__":
        main()

結果

果物	産地	価格
りんご	青森	300
桃	山梨	600
りんご	青森	300
桃	山梨	600

これで完成です。
結果を見ての通り、結合したことにより"りんご","青森","300","桃","山梨","600"の各データが2回ずつCSVファイルに出力されました。

感想

何度かPythonの学習をして来ましたが、一番厄介に感じるのは"インデント"です。
javaやc言語などは、ブロックごとに分けてあるため、インデントでのエラーは発生しません。しかしPythonはインデントがこのブロックに相当するため、インデントにミスがあると、前のインデントから順を追う必要が出てきて大変です。
慣れるまでは時間がかかりそうですが、やれば覚えるの精神で続けて行きます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?