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

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

詳細はこちら
openpyxl

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

Python 3.x

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

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

12498閲覧

python + openpyxl 値を検索し、セルが空白の時に値を入れる

suger365

総合スコア7

openpyxl

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

Python 3.x

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

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2019/12/07 14:36

編集2019/12/08 12:41

初心者ですので不足なコード、記載ミスなどありましたらお教えください。
コードがきれいとはいいがたいのですがどこが悪さしているかわからないのですべて公開します。
コードは長いですが本題は退出記録を記載したいだけなのでそれ以外は飛ばしていただいて構いません。

https://teratail.com/questions/227911
が必要そうな内容を切り抜いて質問させていただいていると思うのですが
不足していそうなので別で質問させていただきます。

不足していませんでした。むしろ単純ミスで、これだけ長いコードを公開したせいで分かりにくくなっていました。
解決した内容を記入しておきましたので許して…

前提・実現したいこと

・セルの値が空白かつIDが一致したときに値をセルに入れたい

・入退出管理システムを作っています
・入室のみのログ、退出のみのログはとれるようになりました
・このままだと二つのログを合わせて計算しないといけません

・システム自体はこのようになっています
ウィンドウに出勤ボタンと退勤ボタンを設定
ボタンが押されたときに4桁の数字かチェックし、OKならSub_Excelを呼び出し
Sub_Excelでは入室記録と退出記録、入退出記録を別で管理。
(入室記録:In_LogLIst.xlsx)
(退出記録:Out_LogList.xlsx)
(入退出記録:Main_LogList.xlsx)←これがうまくいっていない

なのでpython+openpyxlで次のようなことを行いたいです
・入室ログと退出ログを合わせたものを作りたいです。具体的には以下の通り
*入室時に入室時間と社員番号を入れる
*退出時に社員番号が一致し、(かつセルが空白であるとき(この部分は一致したときに入らないので未実装です))退出時間と社員番号を入れる(セルが空白でない=ほかの人が入れているため)
(一致しない場合やほかの人が入れてしまっていてかぶっている場合はエラーリストに入れておく(未実装))

発生している問題・エラーメッセージ

・一致していない扱いなのか退出記録が記録されません。
if ID == EmpNum でID(Excelに記載の社員番号)とEmpNum(GUI側からとってきた社員番号)
が一致した場合はExcelの入室記録のわきに退出記録を入れたいです。

python

1import openpyxl 2from datetime import datetime 3 4def In_Excelwrite(Status,EmpNum): 5 #Excelファイルを開く 6 Inwb = openpyxl.load_workbook(r"C:\python\tkinter\In_LogLIst.xlsx") 7 Inws = Inwb["IN_LIST"] 8 9 #最終行取得など 10 MaxLow = Inwb["IN_LIST"].max_row 11 12 #各種データ 13 d_now = str(format(datetime.now().strftime("%Y/%m/%d %H:%M:%S"))) 14 print(EmpNum,d_now,Status) 15 #出勤にデータを入れる 16 Inws.cell(row = MaxLow + 1 , column = 1 ,value = EmpNum) 17 Inws.cell(row = MaxLow + 1 , column = 2 ,value = d_now) 18 Inws.cell(row = MaxLow + 1 , column = 3 ,value = Status) 19 20 #保存する 21 Inwb.save(r"C:\python\tkinter\In_LogLIst.xlsx") 22 23 ##ここからメインファイル用 24 #メインのExcelファイルを開く 25 Mainwb = openpyxl.load_workbook(r"C:\python\tkinter\Main_LogList.xlsx") 26 Mainws = Mainwb["MAIN_LIST"] 27 28 MainMaxLow = Mainwb["MAIN_LIST"].max_row 29 #メインにデータを入れる**(データが入りません)** 30 Mainws.cell(row = MainMaxLow + 1 , column = 1 ,value = EmpNum) 31 Mainws.cell(row = MainMaxLow + 1 , column = 2 ,value = d_now) 32 Mainws.cell(row = MainMaxLow + 1 , column = 3 ,value = Status) 33 #保存する 34 Mainwb.save(r"C:\python\tkinter\Main_LogList.xlsx") 35 36 #処理完了 37 print("処理が完了しました") 38 39def Out_Excelwrite(Status,EmpNum): 40 #Excelファイルを開く 41 Outwb = openpyxl.load_workbook(r"C:\python\tkinter\Out_LogList.xlsx") 42 Outws = Outwb["OUT_LIST"] 43 44 #最終行取得など 45 MaxLow = Outwb["OUT_LIST"].max_row 46 #各種データ 47 d_now = str(format(datetime.now().strftime("%Y/%m/%d %H:%M:%S"))) 48 print(EmpNum,d_now,Status) 49 #退勤にデータを入れる 50 Outws.cell(row = MaxLow + 1 , column = 1 ,value = EmpNum) 51 Outws.cell(row = MaxLow + 1 , column = 2 ,value = d_now) 52 Outws.cell(row = MaxLow + 1 , column = 3 ,value = Status) 53 54 #保存する 55 Outwb.save(r"C:\python\tkinter\Out_LogList.xlsx") 56 57 ##ここからメインファイル用 58 #メインのExcelファイルを開く 59 Mainwb = openpyxl.load_workbook(r"C:\python\tkinter\Main_LogList.xlsx") 60 Mainws = Mainwb["MAIN_LIST"] 61 62 MainMaxLow = Mainwb["MAIN_LIST"].max_row 63 #メインにデータを入れる ここ違う 64 for row_num in range(1,Mainws.max_row): 65 ID = Mainws.cell(row = row_num , column = 1).value 66 if str(ID) in EmpNum: 67 Mainws.cell(row = row_num , column = 4 ,value = EmpNum)#ここでvalueを入れている位置が違ったようです 68 Mainws.cell(row = row_num , column = 5 ,value = d_now) 69 Mainws.cell(row = row_num , column = 6 ,value = Status) 70 print("ALLRIGHT") 71 else: 72 print("Error") 73 74 #保存する 75 Mainwb.save(r"C:\python\tkinter\Main_LogList.xlsx") 76 77 #処理完了 78 print("処理が完了しました")

試したこと

エラーが出ていないので調べようにも調べられずやれたことは少ないですが…
・IDがStr型なのでEmpNumの型を確認
str型でした。
・実行した結果を確認
入退出記録に入室時のデータは入っているのに退出時のみ記録できません。
・セルが空白であるとき~の条件付けを削除
問題を切り分けるために削除しましたが駄目でした。

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

python 3.8.0

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

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

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

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

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

guest

回答2

0

最初に

今回の問題点は主に二点でした。
1.値が一致したときに入るはずの値が入らない
2.値が一致したときという条件だけではすでに値が入っているセルに入ってしまう
→セルが空白であるときのみ値を入れたい
つまり条件としては「セルが空白であり、かつ値が一致している」
という条件になれば値が一致した、値がまだ入っていないところに値を入れてくれるはずです。

1の解決法

結論から言えば値を入れるための文法が違いました。

カッコ内で"value=xxx"とする場合はほかのところでxxx=yyyとしておかなければならないようです。
今回は行っていなかったのでカッコの外で行わなければならなったようです。

さらに、値が一致するものを見つけた後もfor文が回っているせいで一致する限り何回も値が入ってしまいました。
なので一致した場合はbreakでfor文を抜けさせるようにしました。

また、TaroToyotomi様がおっしゃる通り、pythonのシェルから range(1,10) と入力してみると、10行目まで探してほしいのに9行目までしか探してくれていませんでした。
なので+1しておくことで解決させました(よい解決方法なのかはわかりません)

これらを踏まえた修正後のコードがこちらです

python

1 for row_num in range(1,Mainws.max_row + 1): 2 ID = Mainws.cell(row = row_num , column = 1).value 3 if str(ID) in EmpNum: 4 Mainws.cell(row = row_num , column = 4 ).value = EmpNum 5 Mainws.cell(row = row_num , column = 5 ).value = d_now 6 Mainws.cell(row = row_num , column = 6 ).value = Status 7 print("ALLRIGHT") 8 break 9 else: 10 print("Error")

元のコードがこちらです。

python

1#メインにデータを入れる 2 for row_num in range(1,Mainws.max_row): 3 ID = Mainws.cell(row = row_num , column = 1).value 4 if str(ID) in EmpNum: 5 Mainws.cell(row = row_num , column = 4 ,value = EmpNum) 6 Mainws.cell(row = row_num , column = 5 ,value = d_now) 7 Mainws.cell(row = row_num , column = 6 ,value = Status) 8 print("ALLRIGHT") 9 else: 10 print("Error")

2の解決法

「セルが空白である」ということを考えたときに真っ先にcell.value==""が浮かびました。
が、どうもうまくいかない…

https://stackoverrun.com/ja/q/2033147 では
if sheet.cell(row = 1, column=7).value == None:
print("Blank")

となっているに、cell.value=="" ではなく、cell.value==None
とすれば空白セルを認識してくれる?ようです。

結論

結果、このようなコードになりました

python

1for row_num in range(1,Mainws.max_row + 1): 2 ID = Mainws.cell(row = row_num , column = 1).value 3 if Mainws.cell(row = row_num , column = 4).value == None and str(ID) in EmpNum: 4 Mainws.cell(row = row_num , column = 4 ).value = EmpNum 5 Mainws.cell(row = row_num , column = 5 ).value = d_now 6 Mainws.cell(row = row_num , column = 6 ).value = Status 7 print("ALLRIGHT") 8 break 9 else: 10 print("Error")

これでやりたかったことをやってくれるようになった…と思います。
最後に

最後になりますがTaroToyotomi様、meg_様に感謝申し上げます。ありがとうございました。

投稿2019/12/08 12:35

suger365

総合スコア7

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

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

0

ベストアンサー

今回の問題に関係ないかもですが。。。
**for row_num in range(1,Mainws.max_row):**だと最後の行が参照されなくないですか?

あと、この方法だと同じEmpNumの人が2回入退室した時に2回目以降の退室が記録できないと思いますが。

投稿2019/12/07 19:05

TaroToyotomi

総合スコア1448

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

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

suger365

2019/12/08 04:04

TaroToyotomi 様 ・for row_num は最終行参照になりませんか? range(1,Mainws.max_row)でセル1行目から最終行まで検索させているつもりなのですが… ・同じEmpNumの人が二回入退出~ In_LogListやOut_LogList.xlsxでは入室退出がかぶっても記録は可能なようです。 今回問題となっているMainListでは 入室→退出→入室→退出 の正常系なら動くと思うのですが… 入室→(違う人が間違って)退出→(本人が)退出ではおっしゃる通りうまくいかないかと。
TaroToyotomi

2019/12/08 05:38

Mainws.max_rowがセルに入っている最後の行番号を示しているならNGです。 試しにpythonのシェルから range(1,10) と入力してみればわかると思います。 max_rowが10だと仮定したら期待したリストにならないですよね? 入室(1)→退出(2)→入室(3)→退出(4)で考えます。 入室(3)は、 Mainws.cell(row = MainMaxLow + 1 , column = 1 ,value = EmpNum) とあるので最終行の次の行に追加されます。 退室(4)は、Mainwsの先頭の行からIDを比較しているため、入室(1)の行を一致したと判断しませんか?
suger365

2019/12/08 12:12

TaroToyotomi 様 ご指摘ありがとうございます。 ・Mainws_max_rowが最後の行番号を示しているならNG まさに最後の行番号を表していました… range(1,10)をシェルで入力した場合"range(1, 10)"で帰ってきました。 少し調べてlist(range(1,10))としたところ [1, 2, 3, 4, 5, 6, 7, 8, 9]が出力で、おっしゃる通り10行まで取りたいのに取れていないです! 1プラスして for row_num in range(1,Mainws.max_row+1)とすればいけるかな? ・Mainwsの先頭の行から~ こちらは空白セルでない場合は記入させないように後程実装する予定でした。 問題切り分けのためにいったん保留していた部分です。 「退出時に社員番号が一致し、(かつセルが空白であるとき」と書いてお伝えしたつもりでしたが質問時の書き方が悪かったようで申し訳ないです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問