0. 前提
- やったこと:固定長DATファイルの中身を調べるためにpythonでCSVにした.
- 本文の目的:記録.
- 実行環境:macOS Mojave (version 10.14.6) / shell: fish / Eclipse 2017 (version 4.7.3) / python3 (version 3.7.4)
- Ecpliseでpythonを使う方法はこちらを参考にしました.
1. 固定長DATファイルをtxtファイルにコピーする
ここはターミナルでコマンドを使って、対応しました.
ターミナルを開いて、catコマンドを実行
cat sample.DAT > sample.txt
エラーがでなければ、これでDATファイルはtxtファイルへ変換されました.
catコマンドはファイルの中を閲覧するコマンドです.
つまり,ここではcatコマンドでsample.DATの中を出力し,その結果をsample.txtとして保存しています.
詳細はこちらのサイトへ.
※追記(2019/10/12)
ご指摘いただいたので,追記します.
1ファイルであれば,ただコピーするだけなのでcpコマンドで実行できます.(こっちのほうが自然...
複数ファイルを結合する場合には上記方法で,実行できます.
cp sample.DAT sample.txt
cat sample1.DAT sample2.DAT > sample.txt
2. txtファイルをCSV化する
ここからが本番です.
2.0. やりたいこと
現時点でのtxtファイルはこんな感じです.
2018100400400010234
2018100400050020234
2018100500700010022
これをこんな感じにしたいのです.
購入日,購入金額,行数,顧客番号
20181004,004000,1,0234
20181004,000500,2,0234
20181005,007000,1,0022
なので,pythonでやりたいことはこんな感じになります.
- txtファイルを1行ずつ読み込む
- 読み込んだデータを1行ずつ分割する
- csvとして出力する
2.1. txtファイルを読み込む関数の作成
pandas使うのでインポートします.
import pandas as pd
今回は、複数ファイルをじゃんじゃんやるので関数化しています。
対象ファイルのパスを渡したら、そのファイルを1行ごと読み込んだリストを返します.
def read_file(path): # ファイルのパスを引数として渡す
f = open(path, encoding='utf-8') # ファイルを読み込む
line = f.readlines() # ファイルを1行ずつリスト化する
f.close()
return line
さて、これで1行ずつリストの要素として格納することができました.
返ってきた値はこうなります.
['2018100400400010234\n', '2018100400050020234\n', '2018100500700010022']
改行コードが入ってしまっていますが、今回は問題ないのでこのままにします.
回避方法はこちらの記事に書いてあります.
2.2. 1行ずつ分割する関数の作成
さて,1行ずつ分割をして意味のある値に戻していきます.
2.1.で作成した関数の返り値のリストには,txtファイルの1行が文字列として格納されています.
そのため,さきほどのリストの要素を一つずつ読み込んで,それをスライスで分割してリストに格納します.
def split_line(l):
l_split = l[[0:8], [8:14], [14,15], [15:19]]
return l_split
pythonでは,文字列もリストとして扱えるので,要素数を指定することで,
文字の一部を抽出することができます.
例えば,1行目の'2018100400400010234\n'
を上記のsplit_line
関数に渡すと
返り値はこのようになります.
['20181004', '004000', '1', '0234']
(ヨダン)
ぶっちゃけ区切りを指定しなきゃいけないのはだるいですが,これが最善でした...
どなたかもっと良い方法があれば,ご教授くださいませ.
2.3. CSVとして出力する
split_line
関数をread_file
関数から得たリスト(1段階目)の要素すべてにかけなければなりません.
for文でも一応できますが,数万行あると恐ろしい計算時間になってくるので,map関数を使っていきます.
(pythonの各関数の処理時間を比較している記事は多数あるので,ぜひ参照してみてください.例)
リスト(1段階目)の各要素をsplit_line
関数に渡して実行するため,下記のような処理が必要です.
line = ['2018100400400010234\n', '2018100400050020234\n', '2018100500700010022']
map(split_line, line)
しかし,map関数の返り値はmapオブジェクトなのでそのままでは扱いにくいです.
そのため,今回はそのままDataFrame化してしまいます.
したがって,下記のような関数にリスト(1段階目)を渡して,全行を分割してDataFrame化します.
ここでまとまてカラム名も入れてしまいます.
def to_df(line):
df = pd.DataFrame(map(split_line, line) # 全行を分割して,データフレーム化
df.columns['購入日', '購入金額', '行数', '顧客番号'] # カラム名
return df
to_df
関数にリスト(1段階目)を渡すと,返り値はこうなります.
購入日 購入金額 行数 顧客番号
0 20181004 004000 1 0234
1 20181004 000500 2 0234
2 20181005 007000 1 0022
これをto_csv
関数でCSVで出力すればミッションクリア!
df.to_csv('sample.csv', sep=',', encoding='utf-8')
おつかれさまでした.
3. まとめ
関数ごとに紹介したので,下記に全体像を示します.
# txtファイルを読み込んで,リスト化する
def read_file(path):
f = open(path, encoding='utf-8')
line = f.rearlines()
f.close()
return line
# 1行を分割する
def split_line(l):
l_split = l[[0:8], [8:14], [14,15], [15:19]]
return l_split
# リストの全要素を分割し,データフレーム化
def to_df(line):
df = pd.DataFrame(map(split_line, line)
df.columns['購入日', '購入金額', '行数', '顧客番号']
return df
# txtファイルを読み込み,リスト(1段階目)を得る
List_1 = read_file("./sample.txt")
# リスト(1段階目)をデータフレーム化する
df = to_df(List_1)
# csvへ出力
df.to_csv('sample.csv', sep=',', encoding='utf-8')
4. あとがき
難しいことは何もしていませんが,pythonで文字列データをいじるとっかかりはつかめるような作業でした.