🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
openpyxl

openpyxlは、Excel2007以降のファイル(xlsx/xlsm/xltx/xltm)を読み書きするためのPythonライブラリです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

3615閲覧

[openpyxl] リストに格納した各セル行の文字列を貼り付けるときに、一つのセルにまとめて張り付けられてしまう

daichiddd

総合スコア9

openpyxl

openpyxlは、Excel2007以降のファイル(xlsx/xlsm/xltx/xltm)を読み書きするためのPythonライブラリです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2021/01/08 18:36

前提・実現したいこと

pythonでExcel作業の自動化に取り組んでいます。
主にコピペ作業をさせたいです。
指定したセル行コピーをリストに格納することはできました。
しかしそれを張り付ける際に元のセル行の様にではなく、一つのセルにまとめて張り付けられてしまいます。

enumerate関数のところでつまずいていると思われますが、内容の理解不足もあり、どこが間違っていてこの出力結果になるのか分からないため質問させていただきます。

有識者の方、どうかお力添えください。

該当のソースコード

python

1import os 2import openpyxl as px 3import re 4 5print("< Sheet1 に入っているセルの文字列 >") 6print("") 7 8file_name = r"C:\Users\---\Desktop\MyPandas\test.xlsx" 9wb = px.load_workbook(file_name) 10ws = wb["Sheet1"] 11 12active_sheet_1 = wb.active 13for row in active_sheet_1.rows: 14 excel = [] 15 for cell in row: 16 excel.append(cell.value) 17 print(excel) 18 19# 格納するリスト 20bb_clb = [] 21tf_clb = [] 22pic_clb = [] 23 24# 空行の定義 25def is_empty(cell): 26 return cell is None or not str(cell).strip() 27 28# Excelシートで一列ごとに対応するリストへ格納 29# 部活で格納するリストを分ける 30for row in active_sheet_1.iter_rows(min_row = 5, values_only = True): 31 if all(is_empty(c) for c in row): 32 break 33 if "野球部" in row[4]: 34 bb_clb.append(row) 35 elif "陸上部" in row[4]: 36 tf_clb.append(row) 37 elif "写真クラブ" in row[4]: 38 pic_clb.append(row) 39 40print("") 41print("-------------------------------------------------") 42print("") 43print("< 実行結果 >") 44print("") 45 46 47for i, d in enumerate(tf_clb, start = 1): 48 ws.cell(row = i,column = 1,value = str(d)) 49 50wb.save(file_name) 51 52active_sheet_2 = wb.active 53for row in active_sheet_2.rows: 54 excel_cmp = [] 55 for cell in row: 56 excel_cmp.append(cell.value) 57 print(excel_cmp)

出力結果

< Sheet1 に入っているセルの文字列 > [None, None, None, None, None] [None, None, None, None, None] [None, None, None, None, None] ['名前', '年齢', '性別', '出身', '部活'] ['佐藤', 12, '男', '福島', '緑ヶ丘 写真クラブ'] ['渡辺', 23, '女', '愛媛', '明石 陸上部'] ['山田', 22, 'なし', '京都', 'むべ 野球部'] ['相田', 111, '男', '鹿児島', 'nunu 陸上部'] ------------------------------------------------- < 実行結果 > ["('渡辺', 23, '女', '愛媛', '明石 陸上部')", None, None, None, None] ["('相田', 111, '男', '鹿児島', 'nunu 陸上部')", None, None, None, None] [None, None, None, None, None] ['名前', '年齢', '性別', '出身', '部活'] ['佐藤', 12, '男', '福島', '緑ヶ丘 写真クラブ'] ['渡辺', 23, '女', '愛媛', '明石 陸上部'] ['山田', 22, 'なし', '京都', 'むべ 野球部'] ['相田', 111, '男', '鹿児島', 'nunu 陸上部']

補足情報(FW/ツールのバージョンなど)

python 3.8.5
windows 10

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

以下の質問の続きですね。
[openpyxl] Excelシート内で任意の文字と完全一致するセルが存在する列を格納したい | teratail


しかしそれを張り付ける際に元のセル行の様にではなく、一つのセルにまとめて張り付けられてしまいます。

enumerate関数のところでつまずいていると思われますが

その前のfor文のところが間違っています。

python

1for row in active_sheet_1.iter_rows(min_row = 5, values_only = True): 2 if all(is_empty(c) for c in row): 3 break 4 if "野球部" in row[4]: 5 bb_clb.append(row) 6 elif "陸上部" in row[4]: 7 tf_clb.append(row) 8 elif "写真クラブ" in row[4]: 9 pic_clb.append(row)

append()はリストに新しい要素を一つ作成してその要素に入力したデータを格納するメソッドです。
しかし上のコードの5,7,9行目では1行のデータが格納された変数を事前に作成したリストにappend()を使ってリストに追加してしまっています。
そのため行のデータがまとめて一つの要素に入ってしまい、そのまま一つのセルに書き込まれています。

なので以前の回答でも書いていたはずですが、行のデータ(リストやタプル)を要素ごとに分けて追加したい場合はappend()ではなくextend()を使う必要があります。

参考:Pythonでリスト(配列)に要素を追加するappend, extend, insert | note.nkmk.me

以下のように書き直せば要素ごとに分かれて書き込まれるようになります。

python

1for row in sheet_1.iter_rows(min_row=5, values_only=True): 2 if all(is_empty(c) for c in row): 3 break 4 if "野球部" in row[4]: 5 bb_clb.extend(row) 6 elif "陸上部" in row[4]: 7 tf_clb.extend(row) 8 elif "写真クラブ" in row[4]: 9 pic_clb.extend(row)

  
また書き込みのところですが、

python

1for i, d in enumerate(tf_clb, start = 1): 2 ws.cell(row = i,column = 1,value = str(d))

rowにインデックスの変数iを入れてしまうと縦に書き込まれてしまうので、以下のようにrowとcolumnの値を入れ替える必要があります。
あとstr()で書き込むデータを文字列に変換していますが、数字を文字列として書き込んでしまうとExcelでエラーが表示されてしまうのでstr()は外した方がいいです。

python

1for i, d in enumerate(tf_clb, start=1): 2 ws.cell(row=i, column=1, value=d)

内容の理解不足もあり、どこが間違っていてこの出力結果になるのか分からないため質問させていただきます。

デバッグという機能を使えばコードの処理を1行ずつ確認することができます。
もしお使いのエディタまたはIDEにデバッグ機能がついているなら、意図しない動作をした際はデバッグして1行ずつ確認することをお勧めします。


#####追記(コメントの質問について)

python

for a, tf_clb_list in enumerate(tf_clb, start = 1):
for i in range(1,3):
for j in range(1,6):
ws.cell(row = i, column = j,value = tf_clb_list)

このコードではリストの最初の要素が指定したすべてのセルに書き込まれ、次の要素がすべてのセルに書き込まれ、その次の要素が・・・となってしまっています。

方法としてはいくつか方法がありますが、上のコードを生かすなら以下のようにカウンタ変数を利用する感じでしょうか。

python

1counter = 0 2for i in range(1, 3): 3 for j in range(1, 6): 4 ws.cell(row=i, column=j, value=tf_clb[counter]) 5 counter += 1

ただカウンタ変数を使うのはあまりよくありませんし、データの数が変わったらrange()の部分をいちいち変更する必要がります。

個人的には以下のように行のデータをappend()で各要素に格納して二次元のリストにしてからセルに書き込む方がいいと思います。
上の方法では同じ部活に所属している人のデータが一列の格納されていましたが、この方法では行ごとにデータがきちんと分けられているのでお行儀がいいですし、カウンタ変数は必要ありません。

python

1for row in active_sheet_1.iter_rows(min_row=5, values_only=True): 2 if all(is_empty(c) for c in row): 3 break 4 if "野球部" in row[4]: 5 bb_clb.append(row) 6 elif "陸上部" in row[4]: 7 tf_clb.append(row) 8 elif "写真クラブ" in row[4]: 9 pic_clb.append(row) 10 11print("") 12print("-------------------------------------------------") 13print("") 14print("< 実行結果 >") 15print("") 16 17 18for i, row in enumerate(tf_clb, 1): 19 for j, elem in enumerate(row, 1): 20 ws.cell(row=i, column=j, value=elem)

最終行に書き込んでもいいなら以下のようにワークシートオブジェクトのappend()を使うこともできます。

python

1for row in sheet_1.iter_rows(min_row=5, values_only=True): 2 if all(is_empty(c) for c in row): 3 break 4 if "野球部" in row[4]: 5 bb_clb.append(row) 6 elif "陸上部" in row[4]: 7 tf_clb.append(row) 8 elif "写真クラブ" in row[4]: 9 pic_clb.append(row) 10 11print("") 12print("-------------------------------------------------") 13print("") 14print("< 実行結果 >") 15print("") 16 17 18for bb_clb_elem in bb_clb: 19 ws.append(bb_clb_elem)

新しいシートに書き込むサンプルも載せておきます(少し修正加えてます)。
参考にしてみてください。

python

1import openpyxl as px 2 3 4# シートのデータをすべて表示 5def print_ws_data(ws): 6 for row in ws.iter_rows(values_only=True): 7 print(row) 8 9 10# 空行かどうか判定 11def is_empty(cell): 12 return cell is None or not str(cell).strip() 13 14 15print("< Sheet1 に入っているセルの文字列 >") 16print("") 17 18file_name = r"C:\Users\---\Desktop\MyPandas\test.xlsx" 19wb = px.load_workbook(file_name) 20 21sheet_1 = wb.worksheets[0] 22 23print_ws_data(sheet_1) 24 25# 格納するリスト 26bb_clb = [] 27tf_clb = [] 28pic_clb = [] 29 30# Excelシートで一列ごとに対応するリストへ格納 31# 部活で格納するリストを分ける 32for row in sheet_1.iter_rows(min_row=5, values_only=True): 33 if all(is_empty(c) for c in row): 34 break 35 if "野球部" in row[4]: 36 bb_clb.append(row) 37 elif "陸上部" in row[4]: 38 tf_clb.append(row) 39 elif "写真クラブ" in row[4]: 40 pic_clb.append(row) 41 42print("") 43print("-------------------------------------------------") 44print("") 45print("< 実行結果 >") 46print("") 47 48ws_2 = wb.create_sheet() 49 50for tf_clb_elem in tf_clb: 51 ws_2.append(tf_clb_elem) 52 53wb.save(file_name) 54 55print_ws_data(ws_2) 56

投稿2021/01/09 08:57

編集2021/01/09 19:47
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

daichiddd

2021/01/09 15:55 編集

前回に続き回答ありがとうございます!!!!! 無事一つのセルにすべての要素が転記されることはなくなりました。 extendは見落としていました、、 申し訳ありません。 参考もありがとうございます!
daichiddd

2021/01/09 15:55 編集

お時間あればでよろしいのですが、、、 加えて質問よろしいでしょうか。 一つのセルに転記されることはなくなったのですが、一つの行にすべてのリスト内のデータが転記されるようになりました。 ↓実行結果 ['渡辺', 23, '女', '愛媛', '明石 陸上部', '相田', 111, '男', '鹿児島', '洛南 陸上部'] [None, None, None, None, None, None, None, None, None, None] [None, None, None, None, None, None, None, None, None, None] ['名前', '年齢', '性別', '出身', '部活', None, None, None, None, None] ['佐藤', 12, '男', '福島', '緑ヶ丘 写真クラブ', None, None, None, None, None] ['渡辺', 23, '女', '愛媛', '明石 陸上部', None, None, None, None, None] ['山田', 22, 'なし', '京都', '帝京 野球部', None, None, None, None, None] ['相田', 111, '男', '鹿児島', '洛南 陸上部', None, None, None, None, None]
daichiddd

2021/01/09 15:44

これに対し自分はこのようにコードを編集したのですが、結果は陸上部リストに格納した最後のデータが転記されるようになりました。 ↓コード for a, tf_clb_list in enumerate(tf_clb, start = 1): for i in range(1,3): for j in range(1,6): ws.cell(row = i, column = j,value = tf_clb_list)
daichiddd

2021/01/09 15:46

↓出力結果 < 実行結果 > ['洛南 陸上部', '洛南 陸上部', '洛南 陸上部', '洛南 陸上部', '洛南 陸上部'] ['洛南 陸上部', '洛南 陸上部', '洛南 陸上部', '洛南 陸上部', '洛南 陸上部'] [None, None, None, None, None] ['名前', '年齢', '性別', '出身', '部活'] ['佐藤', 12, '男', '福島', '緑ヶ丘 写真クラブ'] ['渡辺', 23, '女', '愛媛', '明石 陸上部'] ['山田', 22, 'なし', '京都', '帝京 野球部'] ['相田', 111, '男', '鹿児島', '洛南 陸上部']
daichiddd

2021/01/09 15:51

理想の実行結果は以下です ['渡辺', 23, '女', '愛媛', '明石 陸上部'] ['相田', 111, '男', '鹿児島', '洛南 陸上部'] [None, None, None, None, None] ['名前', '年齢', '性別', '出身', '部活'] ['佐藤', 12, '男', '福島', '緑ヶ丘 写真クラブ'] ['渡辺', 23, '女', '愛媛', '明石 陸上部'] ['山田', 22, 'なし', '京都', '帝京 野球部'] ['相田', 111, '男', '鹿児島', '洛南 陸上部']
daichiddd

2021/01/09 15:54

理想の実行結果を得るためにはどのような編集が必要ですか。 enumerateのインデックス番号をうまく利用する方法があるのでしょうか。 調べてもあまりいい例がないので、もしよければ教えていただきたいです。。
退会済みユーザー

退会済みユーザー

2021/01/09 17:02

分かりました。 追記しますね。
daichiddd

2021/01/10 00:30 編集

質問への回答ありがとうございます。 appendとexpendで要所に分けて使い方を変えるんですね、、とても参考になります、、、! コードで冗長な箇所も修正していただいて、感謝してもし足りないです。。
daichiddd

2021/01/10 00:29

デバッグ等さまざまなスキルアップの知識も頂いたのでもっと勉強したいと思います。 またの機会があればよろしくお願いします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問