IVSのセレクタ文字判別用のクラスを作ってみた

とあるChar型の中の文字がIVSセレクタ文字列なのか判別するためのクラスを作ってみました。

System.Globalization.TextElementalEnumeratorではちゃんとセレクタ文字列も判別して動作するようなので、大抵の方は困らないんだろうと思いますが、ちょっと特殊なケースだとString中の1文字や特定のChar型の文字がIVSのセレクタ文字かどうかの判別が必要になったりする場合があるかもしれないので作ってみましたという感じです。

全体のコードはいつも通りGitHubで公開しています。
https://github.com/ishisaka/IvsUtility

namespace OpcDiary
{
    /// <summary>
    ///     IVSセレクタ文字列用のユーティリティクラス
    /// </summary>
    public static class IvsUtility
    {
        //日本の漢字の異字体セレクタはVariation Selector Supplementの範囲だけ使用される
        public const char VariationSelectorSupplementHi = '\uDB40';
        public const char VariationSelectorSupplementLoStart = '\uDD00';
        public const char VariationSelectorSupplementLoEnd = '\uDDEF';
        //それ以外だと以下が使われている可能性がある
        public const char VariationSelectorStart = '\uFE00';
        public const char VariationSelectorEnd = '\uFE0F';
        //モンゴル文字用
        public const char MongolianFreeVariationSelectorStart = '\u180B';
        public const char MongolianFreeVariationSelectorEnd = '\u180d';

        /// <summary>
        ///     文字列中の指定位置の文字がIVSのセレクタ文字列か判断する。
        /// </summary>
        /// <param name="s">文字列</param>
        /// <param name="index">s 内の評価する文字の位置。</param>
        /// <returns>s の index の位置にある文字がセレクタ文字列の場合は true。それ以外の場合は false。</returns>
        public static bool IsVariationSelector(this string s, int index)
        {
            return CheckSelector(s[index]);
        }

        /// <summary>
        ///     文字がIVSのセレクタ文字列か判断する。
        /// </summary>
        /// <param name="c">評価するUNICODE文字</param>
        /// <returns>文字がセレクタ文字列の場合は true。それ以外の場合は false。</returns>
        public static bool IsVariationSelector(this char c)
        {
            return CheckSelector(c);
        }

        /// <summary>
        ///     文字がIVSのセレクタ文字列か判断する。
        /// </summary>
        /// <param name="c">評価するUNICODE文字</param>
        /// <returns>文字がセレクタ文字列の場合は true。それ以外の場合は false。</returns>
        private static bool CheckSelector(char c)
        {
            if (c == VariationSelectorSupplementHi
                || (VariationSelectorSupplementLoStart <= c && c <= VariationSelectorSupplementLoEnd)
                || (VariationSelectorStart <= c && c <= VariationSelectorEnd)
                || (MongolianFreeVariationSelectorStart <= c && c <= MongolianFreeVariationSelectorEnd))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        ///     文字がCJKでよく使われるIVSのセレクタ文字列か判断する。
        /// </summary>
        /// <param name="c">評価するUNICODE文字</param>
        /// <returns>文字がセレクタ文字列の場合は true。それ以外の場合は false。</returns>
        private static bool CheckVariationSelectorSupplement(char c)
        {
            if (c == VariationSelectorSupplementHi
                || (VariationSelectorSupplementLoStart <= c && c <= VariationSelectorSupplementLoEnd))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        ///     文字がIVSのセレクタ文字列か判断する。
        /// </summary>
        /// <param name="c">評価するUNICODE文字</param>
        /// <returns>文字がセレクタ文字列の場合は true。それ以外の場合は false。</returns>
        private static bool CheckVariationSelector(char c)
        {
            if (VariationSelectorStart <= c && c <= VariationSelectorEnd)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        ///     文字がモンゴル語用のIVSのセレクタ文字列か判断する。
        /// </summary>
        /// <param name="c">評価するUNICODE文字</param>
        /// <returns>文字がセレクタ文字列の場合は true。それ以外の場合は false。</returns>
        private static bool CheckMongolianFreeVariationSelector(char c)
        {
            if (MongolianFreeVariationSelectorStart <= c && c <= MongolianFreeVariationSelectorEnd)
            {
                return true;
            }
            return false;
        }
    }
}

さて、UnicodeCategoryをみてもそれらしき分類は定義されていないし、判別用クラスも無いのに、現状では.NETはどの様に内部判断しているから、TextElementalEnumeratorが正しく動いているような気がするんだろうと言うところですが、以下のようなテストコードを書いて調べてみることにします。

using System;
using System.Globalization;

namespace IvsTest2
{
    class Program
    {
        static void Main(string[] args)
        {
            var testString = "渡\u908A\uDB40\uDD07さん";
            for (int i = 0; i < testString.Length; i++)
                Console.WriteLine(CharUnicodeInfo.GetUnicodeCategory(testString, i));
            Console.ReadLine();
        }
    }
}

実行結果

OtherLetter
OtherLetter
NonSpacingMark
Surrogate
OtherLetter
OtherLetter

3文字目と4文字目がセレクタ文字(正確にはセレクタ文字のサロゲートペア)なのですが、それぞれセレクタ文字と言うより、3文字目がNonSpacingMark、4文字目がSurrogateと判断されていて、組み合わせても人としてわかる文字では無いので無視しているんだろうなという感じですね。

UnicodeCategory列挙体にセレクタ文字が加えられたりするとかっこいいんですがねぇ。

One thought on “IVSのセレクタ文字判別用のクラスを作ってみた”

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください