読者です 読者をやめる 読者になる 読者になる

C# でかなに濁点/半濁点がつくか判定する

Dev

図書館のタッチパネルとかで見る、文字パレットを実装する際に濁点や半濁点を別個で入力したときに「あ゜」とかならないように判定する方法を聞かれたので、考えてみた。

UTF-8の特性を利用して、こうすればいいかな?カナ?

using System;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            // 入力
            string input = "は";

            // UTF-8 NFD において他のカナ文字と結合して、濁点/半濁点文字となるもの
            char dakuten    = '\x3099';   // U+3099: COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK
            char handakuten = '\x309A';   // U+309A: COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK

            // NFD風に結合した後、NFCに戻す。
            string added = (input + dakuten).Normalize(NormalizationForm.FormC);

            // NFCにない場合(=文字と濁点の組み合わせが存在しない場合)文字化けして2文字になる
            // 結合前と同じ文字数を示した場合は、その組み合わせが存在する
            if (input.Length == added.Length)
            {
                Console.WriteLine("{0} は {1} になりますなー。", input, added);
            }
            else
            {
                Console.WriteLine("その組み合わせは存在しませんなー。");
            }
        }
    }
}

前にMac OS Xのファイル名の件で引っかかった|20070630#p01、かな文字と濁点/半濁点を分けて表記する「UTF-8 Nomalization Form D」の形式で判定する文字列の末尾に結合用の半濁点または濁点をつけて、そのあと String.Normalize で Nomalization Form C に戻す。

Nomalization Form C にある組み合わせだと「た」が「だ」になるなど、変換前後の文字数に変化がないのですが、存在しない組み合わせは、濁点部分が「 ?」みたいな感じで化けて、Length が結合処理の前後で変わってしまうので、処理前後の Length を比較して、同じであれば濁点/半濁点がつく組み合わせ、変わっていればつかない組み合わせであるといえます。

簡単ですが、あんまり良い方法じゃないかも知れない。もっと良い方法知ってる人がいたら教えてください。