HOME備忘帳

perlで50音順にソート

perlプログラムで、日本語文字列をソートしたいとき、sort関数をそのまま使うと、不自然な並び順にしかなりません。

日本人が自然に感じるのは50音順、アイウエオ順なのですが、sortは文字コード順にしてしまうからです。

sort関数は、並べ替える値同士をどのように比較するか、サブルーチンで指定できます。それを利用して、50音順(アイウエオ順)に並べるサブルーチンを書きました。

もっと便利なモジュールとかあるんじゃないの…?と思いつつ、たいした量のコードでもないので、まあいいかなぁと使っています。

50音順(アイウエオ順)ソート

ひらがなとカタカナを、それなりに納得できる順番に並べる、50音ソート用のサブルーチンです。
漢字はさすがに無理です。ローカル環境や自前サーバで、読み仮名エンジンと連携すればできるでしょうが、レンタルサーバなどではちょっと。

見たとおり、use utf8;前提です。

# 50音順での並び替え
sub jp50 {

	# 1.ひらがな→カタカナ
	my $a1 = $a;
	$a1 =~ tr/ぁ-ゖ/ァ-ヶ/;
	my $b1 = $b;
	$b1 =~ tr/ぁ-ゖ/ァ-ヶ/;

	# 2.濁音・半濁音→清音
	my $a2 = $a1;
	$a2 =~ tr{ガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポヴ}
	         {カキクケコサシスセソタチツテトハヒフヘホハヒフヘホウ};
	my $b2 = $b1;
	$b2 =~ tr{ガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポヴ}
	         {カキクケコサシスセソタチツテトハヒフヘホハヒフヘホウ};

	# 3.拗音→清音、清音→拗音
	my $a3 = $a2;
	$a3 =~ tr{ァィゥェォッャュョヮヵヶアイウエオツヤユヨワカケ}
	         {アイウエオツヤユヨワカケァィゥェォッャュョヮヵヶ};
	my $b3 = $b2;
	$b3 =~ tr{ァィゥェォッャュョヮヵヶアイウエオツヤユヨワカケ}
	         {アイウエオツヤユヨワカケァィゥェォッャュョヮヵヶ};

	   $a3 cmp $b3
	|| $a2 cmp $b2
	|| $a1 cmp $b1
	|| $a  cmp $b;
}

呼び出し方

2つ目の引数としてsortに渡します。たとえばこんなかんじ。

use strict;
use warnings;
use utf8;	# このファイルはutf-8

# windowsのコマンドプロンプトで表示するのでsjis
binmode STDOUT, ":encoding(sjis)";

# サンプルの配列
my @list = qw(あか あが アカ じゃ しゃ しや シャ ジヤ くー くん);

# 通常のソート
@list = sort @list;
print "sort:", join(", ", @list), "\n";

# jp50ルーチンでソート
@list = sort jp50 @list;
print "jp50:", join(", ", @list), "\n";

# ----- SUBS
sub jp50 {
 # 先に書いたコード...
}

結果はこうなります。

sort:あか, あが, くん, くー, しゃ, しや, じゃ, アカ, シャ, ジヤ
jp50:あか, アカ, あが, くん, くー, しや, ジヤ, しゃ, シャ, じゃ

上がsort関数をそのまま使った場合、下が並べ替えに自作ルーチンを使った場合です。
下段なら、まあまあ50音順と言ってもいいかなと。

今回のものは長音「-」の扱いは「ん」より後ろです(文字コード順そのまま)。50音順、と言うとき、そういう並び順もある一方、前の文字の母音と解釈する並び順もあるみたいです。
上の例だと、「くー」を「くう」と解釈して、「くん」より前に並べるということです。

その場合はごにょごにょと、もうすこし正規表現をを書かないといけなさそうですね。

余談

こういうルーチンを書くと、大昔のperl4 & jperlとかの時代を思い出します。当時は、日本語テキストをこねくり回すスクリプトを楽しくたくさん書いていました。

インターネット時代になり、文字コード云々とかで、気軽で強力なテキスト加工がしにくくなったのですが。いまやutf8Encodeのおかげで、またこういうコードが書けます。Perlの中の人に感謝感謝です。

最終更新日:2012/10/26

[ ページ先頭へ ]