C# で文字列を「いろは順」で並び替える
日本年金機構の多くの年金事務所で採用されている「いろは順」だが、残念なことに C# (.NET Framework) では簡単に並び替えられないようだ。仕方がないので来たるべきときに備え、いろは順に並び替えるコードを書いた。
使用イメージはこうだ。サンプルコードではひらがなのみだが、カタカナや漢字などが含まれていても動作する。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var names = new[] { | |
"あさみ りな", | |
"なみき なおと", | |
"いで なおと", | |
"はなおか なつき", | |
"まつうら やすふみ", | |
"おき ようすけ", | |
"おざき あやこ", | |
"うみの さき", | |
"こいけ いくじ", | |
"こじま こうじ"}; | |
// 並び替え | |
foreach (var n in names.OrderBy(i => i, new IrohaComparer())) { | |
Console.WriteLine(n); | |
} | |
// 出力結果 | |
// いで なおと | |
// はなおか なつき | |
// なみき なおと | |
// うみの さき | |
// おざき あやこ | |
// おき ようすけ | |
// まつうら やすふみ | |
// こいけ いくじ | |
// こじま こうじ | |
// あさみ りな | |
} | |
} |
いろは順にソートする Comparer クラスは次のように書いた。動作は保証しないが、自由に使ってもらって構わない。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
以上。