txtファイルをxlsxファイルに変換するコードをpythonで書く

投稿者: | 2020年1月31日

変換というと語弊があるのですが、以下の画像のようになっているテキストファイルがあります。

このテキストファイルを、次のようなxlsxファイルにしたいと思いました。

ということでpythonでコードを書いていきましょう。

さて、pythonのコードを書くわけですが、私はpython初心者です。コードを書き上げる数時間前にpythonに初めて触ったレベルなので、動くコードはかけましたが、きれいなコードは書けないのでご容赦ください。

書いたコード

書いたコードは以下のとおりです。

私の備忘録も兼ねて、どこをどのように調べてこのコードを書いたのか説明をしていきます。

import

[py] import openpyxl as px [/py]

C/C++のincludeみたいなものなんですが、ちょっと違います。pythonは標準ライブラリがすでに読み込まれています。それも膨大な数です。

そのため、この標準ライブラリ外のモジュールをimportしていくわけです。

今回はxlsxファイルに出力するので、openpyxlというモジュールをインポートしています。

また、openpyxlは事前にインストールしておく必要があります。

インストール方法は、コマンドプロンプトを開いて、

[bash] pip install openpyxl [/bash]

とコマンドを打てば大丈夫です。brewみたいに管理できるっぽくて驚いた。

as

ライブラリに好きな名前をつけられます。毎回openpyxlって書くのがめんどくさいので、pxという名前をつけています。

ファイル入力

[py] #ファイルを開く path = r"G:\atom\igarashi\counter_round10.txt" file = open(path) #すべての行をリストとして読み込み lines = file.readlines() #ファイルを閉じる file.close() [/py]

絶対pathをpathという変数に代入します。この時、windows環境だとダブルクオーテーションマークの前にrを付ける必要があります。

これがないと、「該当のファイルやディレクトリはありません」ってエラーが出ます。私はこれで30分ぐらい失いました。

次に、ファイルを開きます。open()関数を使って開けば終わりです。ここでオプションを指定することもできますが、デフォルトで”読み取り専用”なので、よほどのことがなければこのままでいいと思います。

さらに、ファイルを開いたらすべての行を読み込みます。いろいろな読み込み方があるそうですが、今回はすべての行をlistに入れていく方法を取りました。

最後に、ファイルを閉じます。withを使って書けばいらないらしいですが、私は書きました。

ブックを作成

[py] #ブックを新規作成。Workbookの’w’は必ず大文字。 wb = px.Workbook() [/py]

ブックを新規作成します。Workbookのwは大文字じゃないとエラーが出ます。

シートを選択

[py] #アクティブなシートを取得 ws = wb.active [/py]

アクティブなシートを選択します。他にも、シートを作成したりできます。

1列目に0~15を代入する

[py] #1行目に2列目から17列目まで1~15の値をセルに代入 for a in range(1, 17): ws.cell(row=a+1, column=1).value = a-1 [/py]

上にあるExcelのスクショのA列のようにしたかったので、こういう書き方をしました。

rowは行で、columnは列です。間違えないようにしましょう。私は間違えて1時間を失いました。

for文

ただのfor文ですが、C++と大きく異なったものでした。

C++でfor文を書くと、

[cpp] for(int i = 0; i < 10; i++){ //処理 } [/cpp]

のようになります。一番最初に習う形です。

for(初期化式; 条件式; 増減式)の順に書きます。C++03まではこうでしたが、C++11からはもっとスマートな書き方ができるらしいのを今知った。

それはさておき、pythonではfor文を、

for 変数 in データの集合

というふうに書きます。この時点でC++とは大きく違います。

C++の感覚で行くと、inの後ろはbeginとendを指定するものだと思います。しかし、ここにあるのは”データの集合”であって、条件式ですらありません。なので、この部分にrange()を置くこともあれば、stringを置くこともあれば、listを置くこともあります。

そのため、文字列から一文字ずつ取り出すときは、C++なら

[cpp] string s = "Hello"; for(int i = 0; i < 5; i++){ cout << s[i] << endl; } [/cpp]

と書きますが、pythonなら

[py] for char in ‘Hello’: print(char) [/py]

で終わりです。いや、charという変数を使えるのすら驚きなんですけど。

コードの参考:

ということで、現時点で私は、”データの集合”のsizeの分だけループが周り、変数には”データの集合”から取り出された値が代入されていると解釈しています。正しいのかはわからん。

for文一つとってもC++と違いすぎて、頭を抱えていました。

splitしてcellに書き込む

[py] #listを取得するための変数 l = 0 #セルへの書き込み for i in range(2,130): for j in range(1,18): blank = lines[l].split() ws.cell(row=j, column=i).value = int(blank[len(blank)-1]) l += 1 [/py]

pythonのfor文に慣れていないので、C++で書くような感じで書きました。

ここでは、C++には無いsplit関数を使います。C++はsplit関数を自分で作らないとダメです。区切り文字で区切って返すぐらいならgetline関数使えばすぐに作れるんですけど。

さて、splitですが、返り値はリストになります。

この箇所が一番つまずいた部分です。

一番上のtxtファイルのスクショでは、1行目は0のみ、2行目以降は”0 2091132″というふうにスペースで区切りが入ってます。

そのため、1行目をsplitすると、0のみが入った要素数1のlistが戻り値となります。

しかし、2行目以降をsplitすると、0と2091132が入った要素数2のlistが戻り地となります。

この要素数の差が曲者で、もともと以下のように書いていました。

[py] if j == 0: ws.cell(row=j,column=i).value=int(blake[0]) else: ws.cell(row=j,column=i).value=int(blake[1]) [/py]

0行目なら1要素しかないので、listの1番目を取ってくる。それ以降なら2要素なのでlistの2番目を取ってくる、としたわけです。

しかし、このような書き方をすると、out of rangeとエラーが出ます。

どうやら、elseの方も一応評価されているっぽいです。よくわからんけど。

悩んだ挙げ句、最終的にlistの要素数が変わるんだから、要素数-1なら行けるんじゃね?ってことで、こうなりました。苦肉の策です。

len()

オブジェクトのサイズを取得できます。

int()

intといえば整数型なんですが、なんとpythonでは関数にあります。

機能はC++でいうstring_to_intと同じです。最初見たときは、「型キャストでいけるんか~」と思っててましたが、まさかの関数。世界が違う。

これは最後に付け加えた部分なのですが、このままセルに書き込むと文字列として書き込まれます。

その結果、次のようになったので、文字列を整数型に変換してから書き込むようにしました。Excelないでも文字列を数列にできるんですが、いちいちやるのがめんどくさいので、書き込む前に整数型に変換しました。

ブックを保存する

[py] #ブックを保存する wb.save(filename) [/py]

ブックを保存して終わりです。

おわり

いつもC++を書いていたので、pythonのコードを書いている時に違和感しか感じませんでした。便利だなあと思う部分もあれば、これでいいのかってなる部分もありました。

chachaをC++で実装してるときに、pythonのコードを参考にさせてもらったこともありましたが、やはりpythonも書けないとダメだなあと思いました。

卒論終わったらpythonとRustを学んでみようかと思っています。

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください