Development

C# で文字列を「いろは順」で並び替える

日本年金機構の多くの年金事務所で採用されている「いろは順」だが、残念なことに C# (.NET Framework) では簡単に並び替えられないようだ。仕方がないので来たるべきときに備え、いろは順に並び替えるコードを書いた。

年金事務所

使用イメージはこうだ。サンプルコードではひらがなのみだが、カタカナや漢字などが含まれていても動作する。

Program.cs
class Program
{
    static void Main(string[] args)
    {
        var names = new[] {
            "あさみ りな",
            "なみき なおと",
            "いで なおと",
            "はなおか なつき",
            "まつうら やすふみ",
            "おき ようすけ",
            "おざき あやこ",
            "うみの さき",
            "こいけ いくじ",
            "こじま こうじ"};

        // 並び替え
        foreach (var n in names.OrderBy(i => i, new IrohaComparer())) {
            Console.WriteLine(n);
        }

        // 出力結果
        // いで なおと
        // はなおか なつき
        // なみき なおと
        // うみの さき
        // おざき あやこ
        // おき ようすけ
        // まつうら やすふみ
        // こいけ いくじ
        // こじま こうじ
        // あさみ りな
    }
}

いろは順にソートする Comparer クラスは次のように書いた。動作は保証しないが、自由に使ってもらって構わない。

IrohaComparer.cs
using System;
using System.Collections.Generic;
using System.Globalization;

public class IrohaComparer : IComparer<string>
{
    private string iroha = "ィィぃイイいロロろハハはバばパぱニニにホホほボぼポぽヘヘへベべペぺトトとドどチチちヂぢリリりヌヌぬルルるヲヲをヺヮゎワワわヷヵゕカカかガがョョょヨヨよタタたダだレレれソソそゾぞッッっツツつヅづネネねナナなララらムムむゥゥぅウウうヴゔヰゐヸノノのォォぉオオおククくグぐャャゃヤヤやママまヶゖケケけゲげフフふブぶプぷココこゴごェェぇエエえテテてデでァァぁアアあササさザざキキきギぎュュゅユユゆメメめミミみシシしジじヱゑヹヒヒひビびピぴモモもセセせゼぜススすズずンンん";

    public int Compare(string x, string y)
    {
        // null の方が小さい
        if (x == null && y == null) return 0;
        if (x == null) return -1;
        if (y == null) return 1;

        // 1文字ずつ比較
        var xsi = new StringInfo(x);
        var ysi = new StringInfo(y);
        var xlen = xsi.LengthInTextElements;
        var ylen = ysi.LengthInTextElements;
        var xidx = StringInfo.ParseCombiningCharacters(x);
        var yidx = StringInfo.ParseCombiningCharacters(y);

        for (int i = 0; i < Math.Min(xlen, ylen); i++)
        {
            var xc = StringInfo.GetNextTextElement(x, xidx[i]);
            var yc = StringInfo.GetNextTextElement(y, yidx[i]);
            if (xc == yc) continue;

            var xi = iroha.IndexOf(xc);
            if (xi < 0) return xc.CompareTo(yc);
            var yi = iroha.IndexOf(yc);
            if (yi < 0) return xc.CompareTo(yc);

            if (xi < yi) return -1;
            if (xi > yi) return 1;
        }

        // 文字数の短い方が小さい
        if (xlen < ylen) return -1;
        if (xlen > ylen) return 1;
        return 0;
    }
}

以上。

リンク