Pythonの標準モジュールre
を用いて以下のようにスペースで区切られたデータをカンマ区切りのcsvファイルに変換します。
datetime data1 data2
2019-01-01 15 25
2019-01-02 20 30
2019-01-03 25 40
datetime,data1,data2
2019-01-01,15,25
2019-01-02,20,30
2019-01-03,25,40
環境
- Ubuntu16.04(WSL1)
- Python3.6
pythonの標準モジュールしか利用していないので、たいていのpython環境でも問題なく動作すると思います。
実行はLinuxのshellからを行っています。(最近ではWindows環境でもWindows Subsystem for Linux等を使えば容易にLinux環境を構築することができるようになってきました。)
プログラムの作成
モジュールのインポート
import re
import sys
re
はpythonで正規表現を扱うモジュールです。またsys
はコマンドライン引数を指定してpythonにスペース区切りのファイルを渡すために利用します。
変換の準備
スペース区切りをカンマ区切りに変換するために正規表現の文字列のパターンと、入力するファイル、出力するファイルを準備します。
pattern=re.compile(' +') #' +'で一文字以上のスペースを正規表現のパターンとして定義
ifile=sys.argv[1] #入力するファイル名をコマンドライン引数から受け取る
fout=open('c'+ifile.split('.')[0]+'.csv','tw') #出力ファイル名を入力ファイルから命名してopen
sys.argv[0]
は実行ファイル名自体が返されます。
入力ファイルがtest.txt
であった時、出力ファイルはctest.csv
となります。
入力ファイルを一行ずつ読み込んで出力ファイルに書き込み
with open(ifile,'tr') as fin:
for iline in fin:
fout.write(pattern.sub(',',iline)) #一文字以上のスペースをカンマに置換
ofile.close()
入力ファイルはwith
で自動的に閉じられますが出力ファイルは自分で閉じておく必要があります。
コメントで教えていただきましたが入力ファイルと出力ファイルともにwithでまとめて記述することができるようです。
with open(ifile,'tr') as fin \
open('c'+ifile.split('.')[0]+'.csv','tw') as fout:
追記:csvモジュールを使う
コメントで指摘いただいた通りcsvモジュールを使った方が圧倒的に適切です。
コードを引用させていただきます。
mkcsv.pyimport csv import sys assert len(sys.argv) == 2 fname_in = sys.argv[1] fname_out = 'c{}.csv'.format( ''.join(fname_in.split('.')[:-1]) ) with open(fname_in, newline='') as fin, \ open(fname_out, mode='w', newline='') as fout: reader = csv.reader(fin, delimiter=' ', skipinitialspace=True) writer = csv.writer(fout) writer.writerows(reader)
コード全体(非推奨)
#! /usr/bin/python3
import re
import sys
pattern=re.compile(' +')
ifile=sys.argv[1]
ofile=open('c'+ifile.split('.')[0]+'.csv','tw')
with open(ifile,'tr') as fin:
for iline in fin:
ofile.write(pattern.sub(',',iline))
ofile.close()
シェバン行にpythonパスを書いておくと直接ファイルを実行できます。環境に応じて変更してください。
実行
$ python3 mkcsv.py test.txt
シェバン行を書いた場合
$ ./mkcsv.py test.txt
(個人的に)よく使うコマンドなので~/bin
下にmkscv.py
を置いてパスを通しておくと便利です。
この場合どこのディレクトリからでもmkcsv.py
が実行できます。
$ mkcsv.py test.txt
補足1
上述のコードはカレントディレクトリにあるファイルにしか正常に動作しません。
入力ファイルからディレクトリのパスとファイル名に分離したりするとより汎用性を高められるかもしれません。
補足2
これくらいの置換ならわざわざpythonで書くよりもシェルスクリプトとawk
とかsed
を組み合わせて作った方がいいかもしれません。
以下awkを使って書いたコードです。
#! /bin/bash
filename=$(echo "$1" | awk 'BEGIN{ FS ="."}{ print $1}')
awk -v OFS="," '{$1=$1; print $0 }' $1 > c"$filename".csv
rm $1