古い記事
ランダムジャンプ
新しい記事
タイトル文字列だけを使ってシリーズもの(本やDVDなど)を巻数順にソートする方法のメモ。
なんの新規性もない昔から使われている雑なロジックだけど、だいたいはこれで用をなす。

ソートに使う巻数(または年月日)表示の文字は0から9までの10種類。
全角も対象。

テストデータ (test.txt):
ごじょかいは誤じょ解 10
ごじょかいは誤じょ解 4
ごじょかいは誤じょ解 6
今日のステマ料理(10)
今日のステマ料理(1)
今日のステマ料理(5)
今日のステマ料理(11)
暗黒歴史のダイアリー 1
暗黒歴史のダイアリー 2
暗黒歴史のダイアリー 13
週刊漫画GOJO 2016年11月号
週刊漫画GOJO 2016年12月号
週刊漫画GOJO 2016年9月号

単純にソートすると、数値ではなく文字列としてのソートなので、2桁以上の数字ではおかしくなる。下記のように10が4より前になったり。

% sort test.txt
ごじょかいは誤じょ解 10
ごじょかいは誤じょ解 4
ごじょかいは誤じょ解 6
今日のステマ料理(1)
今日のステマ料理(10)
今日のステマ料理(11)
今日のステマ料理(5)
暗黒歴史のダイアリー 1
暗黒歴史のダイアリー 13
暗黒歴史のダイアリー 2
週刊漫画GOJO 2016年11月号
週刊漫画GOJO 2016年12月号
週刊漫画GOJO 2016年9月号

数字を認識し桁を揃えたものに置き換えたのち全体を文字列として比較するという方針で解決。

seriessort.pl :
#!/usr/bin/env perl
# -*- coding: utf-8 -*-
use strict;
use warnings;
use utf8;
use open ":utf8";
binmode STDIN, ":utf8";
binmode STDOUT, ":utf8";

my @list;
while (<>) {
    chomp;
    my $str4sort = $_; # ソート用比較文字列
    $str4sort =~ tr/0123456789/0123456789/; # 全角to半角
    $str4sort =~ s{(\d+)}{sprintf("%08d", $1)}eg; # 桁揃え
    push @list, {str => $_, str4sort => $str4sort};
}

foreach (sort {$a->{str4sort} cmp $b->{str4sort}} @list) {
    print "$_->{str}\n";
    #print "$_->{str4sort}\n";
}

先ほどのテストデータを処理してみると、想定通りにソートできている。

% ./seriessort.pl < test.txt
ごじょかいは誤じょ解 4
ごじょかいは誤じょ解 6
ごじょかいは誤じょ解 10
今日のステマ料理(1)
今日のステマ料理(5)
今日のステマ料理(10)
今日のステマ料理(11)
暗黒歴史のダイアリー 1
暗黒歴史のダイアリー 2
暗黒歴史のダイアリー 13
週刊漫画GOJO 2016年9月号
週刊漫画GOJO 2016年11月号
週刊漫画GOJO 2016年12月号

実際に内部でソートの比較で使われている文字列はこうなる。

ごじょかいは誤じょ解 00000004
ごじょかいは誤じょ解 00000006
ごじょかいは誤じょ解 00000010
今日のステマ料理(00000001)
今日のステマ料理(00000005)
今日のステマ料理(00000010)
今日のステマ料理(00000011)
暗黒歴史のダイアリー 00000001
暗黒歴史のダイアリー 00000002
暗黒歴史のダイアリー 00000013
週刊漫画GOJO 00002016年00000009月号
週刊漫画GOJO 00002016年00000011月号
週刊漫画GOJO 00002016年00000012月号

完全ではないにしろ、大体のケースはこれでなんとかなる。桁があふれなければ、「1.10.2」みたいなバージョン表記も大丈夫。

なお、下記の例のようにシリーズものでありながら巻数表記が統一できてないものはどうしようもない。ありがちな巻数表記パターンを羅列すればなんとかなるだろうが面倒なのでスルー。

ごじょかいは誤じょ解 (4)
ごじょかいは誤じょ解 第6巻
ごじょかいは誤じょ解 10