背景
https://qiita.com/ozaki25/items/33a57ad7eea55822c764 でPythonでもだれか。。。というお話だったので
ちらっとSlackで書いたのですが「解説して〜」(たぶん)というお話を頂きましてザクっと書きます。
なお書き方は自分の趣味的な感じになっていますのでもっといい書き方があるよ!って方はぜひ教えてくださいませ。
やること
ざくっと書いたPythonコードの説明
環境
ubuntu 18.04 + python 3.7.6 です。
$ cat /proc/version
Linux version 4.15.0-111-generic (buildd@lcy01-amd64-011) (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)) #112-Ubuntu SMP Thu Jul 9 20:32:34 UTC 2020
$ python3 -V
Python 3.7.6
投稿したコード
import os
import re
from glob import glob
p_file = glob("./*.csv")
_ = [ os.rename(file, re.sub(r'^.*_([0-9]{1,3}).*(\.csv)$', r'\1\2', file)) for file in p_file ]
Slackに貼り付けたコードが何ゆえか勝手に変換されてて変なコードになってました。
正しくはこちらのコードをみてください。
結果こうなったのはエントリー主が「ワンライナー」を主張してたので。。
もちろんPythonもCLIあるのでやれます、だけどわけわからん状態になるのでここで止めました。
データ作成もワンライナーで?ということなので少々反則っぽいけど。
!touch aaa_1.csv;touch aaa_2.csv;touch aaa_4.csv;touch aaa_9.csv;touch aaa_10.csv;touch aaa_99.csv;touch aaa_100.csv;touch aaa_999.csv;touch aaa_1000.csv
さて説明です。
import os
import re
from glob import glob
ファイルリネームには os.rename
ファイル名置換に正規表現 re
を使いました。
ファイル一覧オブジェクト取得にはglobを使いました。同類っぽいpathlibを最近は使うようにしてます、もうjoinは使ってないです。
p_file = glob("./*.csv")
globを使ってファイル一覧オブジェクトを取得します。余計なファイルを対象にしたくなかったのですがglobが回数マッチをサポートしていないのでとりあえず拡張子csv全部取ってこい、というイマイチな書き方になっています。
・・・ちょっとハマりました。
_ = [ os.rename(file, re.sub(r'^.*_([0-9]{1,3}).*(\.csv)$', r'\1\2', file)) for file in p_file ]
はい、ぱっと見慣れてないとわかりません。
内包表記を使って行数を減らしました(違うメリットもあるのですが)。
内包を使わずに書けばこんな感じです。
for file in p_file:
re_file = re.sub(r'^.*_([0-9]{1,3}),*(\.csv)$', r'\1\2',p_file)
os.rename(file, re_file)
_ に結果代入をしているのはさほど意味はなく指定しないとコンソールログが美しくなかったので出さないようにした苦肉の策です。
[None, None, None, None, None, None, None, None, None, None]
なんだよ。。。これ。
最後は正規表現で
数値1〜3桁を含む部分と拡張子の部分を抜き出して組み立ててます(定番のマッチ+置換)。ちょっと正規表現での絞り込みが甘いかもですが。
r'^.*_([0-9]{1,3}).*(\.csv)$' ⇛ r'\1\2'
r(row文字列表現)を使うと余計なエスケープを使わずに表現できるのでおすすめです。
寄り道
ファイルの読み込み権限とか何かと気になるところですが今回は省略してます。ただ無人実行するような運用をする場合は基本的な存在チェック/読み書き権限などは入れたほうが良いです。
os.renameで失敗するかもなのでtry〜exceptもやったほうがいいですね。今回は手っ取り早くを主眼にしてますのでサボりました(言い訳)
会社で使っているコードではCSVファイルを読んでDataFrameに取り込む処理をやっていますが存在チェック、読み/書きチェックをラップしたClassを作って運用してます。
終わりに
最近異動があって、担当案件の全容が見えてくるにつれてプレッシャーで胃が。。。
Pythonコードを書くとホッとしますね(冗談です)。