カテゴリ:Python・ファイル整理
「写真_1.jpg、写真_2.jpg、写真_10.jpgの順で処理したいのに、10が2より先に来る」。
Pythonでファイル名のリストを並べるときは、名前全体ではなく、番号を数値にして比べると直せます。
1 文字の順番と、番号の順番は違う
sorted(names)で名前の文字列をそのまま並べると、写真_1.jpg、写真_10.jpg、写真_2.jpgの順になります。数字が入っていても、ファイル名は文字列だからです。
順番だけが問題なら、元のファイル名を変更する必要はありません。並べ替えに使う番号だけを取り出します。
2 3つの名前で試す
下の例は、名前が「写真_半角の番号.jpg」の形でそろっている場合に使います。フォルダーの場所を含まない、ファイル名だけのリストが対象です。
Python 3が使える環境で、コード部分だけをUTF-8の「sort_filenames.py」として保存し、普段使っている方法で実行してください。追加ライブラリは不要です。ここではLinux/Python 3.12.14で確認しています。
実物の画像は用意しなくてかまいません。この例は3つの文字列を並べて表示するだけで、ファイルの読み込み・保存・移動・名前変更はしません。
【プログラムここから】
import re
names = ["写真_1.jpg", "写真_10.jpg", "写真_2.jpg"]
pattern = re.compile(r"写真_([0-9]+)\.jpg")
bad_names = [name for name in names if pattern.fullmatch(name) is None]
if bad_names: raise ValueError(f"対象外の名前です: {bad_names[0]!r}")
ordered_names = sorted(names, key=lambda name: int(pattern.fullmatch(name).group(1)))
for name in ordered_names: print(name)
【プログラムここまで】
表示される結果
写真_1.jpg
写真_2.jpg
写真_10.jpg
「プログラムここから/ここまで」の行はコードに含めません。この例では各行の先頭に空白は不要です。
pattern.fullmatchで名前全体の形を先に確認し、対象外がなければ番号の部分をintで整数にして並べます。sortedのkeyは「何を比べて並べるか」の指定です。
並べ替えた結果はordered_namesに入ります。元のnamesの並び順と、名前の文字列はそのままです。
3 自分の一覧に使う前に、名前の形を確認する
まずnamesの3件を、自分のファイル名の例に置き換えて、表示だけで確認します。このコードのまま使えるのは「写真_1.jpg」のような形です。.JPGや.png、別の接頭辞には、そのままでは対応しません。
たとえばREADME.txtや写真_2026_2.jpgが混ざると、「対象外の名前です」というValueErrorで止まります。対象外の名前を勝手に飛ばしたり、どの数字で並べるか推測したりしないためです。
・写真_2.jpgと写真_02.jpgは、どちらも番号2として比べます。名前の0は消えず、この2件の前後は元のリスト順のままです。
・年と連番など、数字が2か所ある場合は、どちらを優先するか先に決めます。この例では扱いません。
・数字のない名前や別形式の名前を、最後に回すか除外するかも別のルールです。必要なファイルを落とさないよう、混ぜたまま流用しないでください。
実際の処理につなぐときは、意図した順になったordered_namesを使います。元のnamesを使い続けると、処理の順番は変わりません。フォルダーの画面表示順を変更するコードでもありません。
まずは、どの番号を基準にしたいかと、表示された順番が合っているかを確かめましょう。
参考:Python公式ドキュメント
ソートのテクニック(sorted、key、同じキーの順序)
re.fullmatch(名前全体の形式確認)