5
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

固定長のファイルをpythonでごりごりCSV化した話。

Last updated at Posted at 2019-10-11

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ファイルはこんな感じです.

sample.txt
2018100400400010234
2018100400050020234
2018100500700010022

これをこんな感じにしたいのです.

sample.csv
購入日,購入金額,行数,顧客番号
20181004,004000,1,0234
20181004,000500,2,0234
20181005,007000,1,0022

なので,pythonでやりたいことはこんな感じになります.

  1. txtファイルを1行ずつ読み込む
  2. 読み込んだデータを1行ずつ分割する
  3. csvとして出力する

2.1. txtファイルを読み込む関数の作成

pandas使うのでインポートします.

pandasインポート
import pandas as pd

今回は、複数ファイルをじゃんじゃんやるので関数化しています。
対象ファイルのパスを渡したら、そのファイルを1行ごと読み込んだリストを返します.

txtファイル読み込み
def read_file(path):  # ファイルのパスを引数として渡す
    f = open(path, encoding='utf-8')  # ファイルを読み込む
    line = f.readlines()  # ファイルを1行ずつリスト化する
    f.close()
    return line

さて、これで1行ずつリストの要素として格納することができました.
返ってきた値はこうなります.

リスト(1段階目)
['2018100400400010234\n', '2018100400050020234\n', '2018100500700010022']

改行コードが入ってしまっていますが、今回は問題ないのでこのままにします.
回避方法はこちらの記事に書いてあります.

2.2. 1行ずつ分割する関数の作成

さて,1行ずつ分割をして意味のある値に戻していきます.
2.1.で作成した関数の返り値のリストには,txtファイルの1行が文字列として格納されています.
そのため,さきほどのリストの要素を一つずつ読み込んで,それをスライスで分割してリストに格納します.

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関数に渡すと
返り値はこのようになります.

リスト(2段階目)
['20181004', '004000', '1', '0234']

(ヨダン)
ぶっちゃけ区切りを指定しなきゃいけないのはだるいですが,これが最善でした...
どなたかもっと良い方法があれば,ご教授くださいませ.

2.3. CSVとして出力する

split_line関数をread_file関数から得たリスト(1段階目)の要素すべてにかけなければなりません.
for文でも一応できますが,数万行あると恐ろしい計算時間になってくるので,map関数を使っていきます.
(pythonの各関数の処理時間を比較している記事は多数あるので,ぜひ参照してみてください.)

リスト(1段階目)の各要素をsplit_line関数に渡して実行するため,下記のような処理が必要です.

map関数
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段階目)を渡すと,返り値はこうなります.

to_dfの返り値
     購入日    購入金額  行数  顧客番号
0  20181004  004000  1  0234
1  20181004  000500  2  0234
2  20181005  007000  1  0022

これをto_csv関数でCSVで出力すればミッションクリア!

to_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で文字列データをいじるとっかかりはつかめるような作業でした.

5
6
4

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
5
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?