0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonで資料ファイルを番号順に並べる自然順ソート

0
Posted at

資料1、資料10、資料2。サンプルのファイル名をPythonで並べると、10が2より先に来ました。配布資料に連番を振るなら、僕はこの順番を先に確かめます。番号どおりに処理したい仕事では、並べ替えも仕様の一部です。

今回は、名前の中の数字を整数として比べる「自然順ソート」を使います。全角数字とゼロ埋めも含めて試しました。ファイル名は変更せず、処理する順番だけをそろえます。

まず、文字列の順番を確かめる

sorted()は、ファイル名に付けた連番の意味までは読み取りません。文字列を先頭から比較するので、資料10.txtと資料2.txtでは、最初に違う文字の1と2で順番が決まります。

資料が9件の間は気づきにくいです。

ファイルを順に読み込んで一つの配布資料にまとめる処理なら、10件目からページ順が変わります。後工程で開き直して確認する手間を減らすため、読み込む手前で順番を固定します。

数字の部分だけを整数にする

次のコードをorder_docs.pyとして保存し、python3 order_docs.pyで実行します。追加ライブラリは不要です。検証環境はCPython 3.14.8、macOS(Darwin 25.6.0)です。

import re

DIGITS = str.maketrans("0123456789", "0123456789")

def natural_key(name):
    text = name.translate(DIGITS)
    parts = re.split(r"([0-9]+)", text)
    key = tuple(int(p) if i % 2 else p
                for i, p in enumerate(parts))
    return key, name

files = ["資料1.txt", "資料10.txt", "資料2.txt",
         "資料02.txt", "資料3.txt"]
expected = ["資料1.txt", "資料02.txt", "資料2.txt",
            "資料3.txt", "資料10.txt"]

ordered = sorted(files, key=natural_key)
assert ordered == expected
assert sorted(reversed(files), key=natural_key) == expected
print("文字順:", ", ".join(sorted(files)))
print("番号順:", ", ".join(ordered))

実行結果です。二つのassertも通りました。

文字順: 資料02.txt, 資料1.txt, 資料10.txt, 資料2.txt, 資料3.txt
番号順: 資料1.txt, 資料02.txt, 資料2.txt, 資料3.txt, 資料10.txt

re.split()の丸括弧は、区切りに使った数字も結果へ残すために付けています。手元の標準ライブラリのヘルプでも、キャプチャした部分を返す仕様を確認しました。資料02.txtなら、分割結果は['資料', '02', '.txt']です。

添字が1・3・5…の部分に数字が入るので、そこだけint()で変換します。比較用の値は('資料', 2, '.txt')。これで2と10を数として比べられます。

変換するのは比較用の文字列だけです。

全角数字の3も比較時には3として扱います。translate()には数字10文字だけの変換表を渡しました。英字の大文字・小文字や記号まで一緒にそろえると、別の名前を同じ扱いにしてしまうので、今回は数字に絞っています。

同じ番号があったら、元の名前で決める

資料02.txtと資料2.txtは、整数にするとどちらも2です。そこでreturn key, nameの後半に元の名前を置きました。同じ番号なら元の文字列で比べるルールです。今回は02が先になります。

Pythonのソートは安定しているので、比較用の値が同じ要素は入力順を保ちます。ただ、フォルダから得た一覧の順番に仕事を任せたくありません。入力を逆順にした二つ目のassertで、同じ結果に戻ることも確かめています。

実ファイルに使う場合は、ファイル名の一覧を並べ、得られた順番で読み込みます。pathlib.Pathの一覧なら、キーにはlambda p: natural_key(p.name)を渡します。並べ替えても、ファイル自体の名前や中身は変わりません。

なお、この関数は連番の非負整数を想定しています。小数や日付、製品の版番号には、それぞれの比較ルールが必要です。空のフォルダを処理してよいかも、呼び出す側で決めます。

僕もこの5個の名前で空ファイルを作り、Pathの一覧から同じ順番になることを確認しました。全角の3は出力にも残っています。比較用に変換した名前でファイルを探し直す手間がないのは助かります。

配布資料が増える運用では、10番以降の並び違いが繰り返し出ると見ています。最初に1・2・10をテスト用の一覧へ入れておけば、処理を変えた日にも順番を確認できます。同じ番号を許すなら、02と2の扱いも担当者間で決めておきます。まず、読み込み前のsorted()へこのキー関数を渡してください。

0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?