ひらがな判定
ひらがなに限った話ではない(カタカナとか漢字とか)けど、プログラム言語側でひらがなカタカナ等々の認識をするのは意外とめんどくさく、かつ意外とライブラリに用意されていない。
C#でも、特にそういった判別をするメソッドはクラスライブラリには入っていない(はず)。
VB.NETには用意されているので、世のC#erはそれを使っている様だが、僕はなんとなくそれが嫌で、自作の判定メソッドを作っている。
ひらがなの判定は大まかには2通り。
- 文字コードを見て、範囲で決定
- ひらがなの集合を用意して、集合に存在するかで判定
それぞれ、メリットとデメリットがある。
1番は、コードを書くのが楽。あと、範囲指定なので漢字の様な膨大な量の文字種にも対処出来る。 2番は、拡張が楽。集合に入れ忘れとかあった場合に簡単に追加出来る。ただ、そもそも入れ忘れんな、って話だよね、まあ。
なので、1番の方が頭の良いやり方だと思っていた。 しかし、ふと「どっちが早いんだろう?」と思ったので、実際に実験してみた。個人的には、文字コードによる判定の方が早いと思っていたのだが……。
1番目の方法。
public static bool IsKana(string target) { foreach (var chara in target) { var charaData = Encoding.UTF8.GetBytes(chara.ToString()); if (charaData.Length != 3) { return false; } var charaInt = (charaData[0] << 16) + (charaData[1] << 8) + charaData[2]; if (charaInt < 0xe38181 || charaInt > 0xe38293) { return false; } } return true; }
2番目の方法。
public static bool IsKana2(string target) { foreach (var chara in target) { var kanas = new string[]{ "あ","い","う","え","お", "か","き","く","け","こ", "さ","し","す","せ","そ", "た","ち","つ","て","と", "な","に","ぬ","ね","の", "は","ひ","ふ","へ","ほ", "ま","み","む","め","も", "や","ゆ","よ", "ら","り","る","れ","ろ", "わ","を","ん", "が","ぎ","ぐ","げ","ご", "ざ","じ","ず","ぜ","ぞ", "だ","ぢ","づ","で","ど", "ば","び","ぶ","べ","ぼ", "ぱ","ぴ","ぷ","ぺ","ぽ", "ぁ","ぃ","ぅ","ぇ","ぉ", "っ", "ゃ","ゅ","ょ", "ゎ", }; if (!kanas.Contains(chara.ToString())) return false; } return true; }
テストプログラムはこんな感じ。
Assert.IsTrue(Program.IsKana("ああ")); Assert.IsFalse(Program.IsKana("アアア")); Assert.IsFalse(Program.IsKana("阿嗚呼")); Assert.IsFalse(Program.IsKana("0123")); Assert.IsFalse(Program.IsKana("0123")); Assert.IsFalse(Program.IsKana("ABC")); Assert.IsFalse(Program.IsKana("ABC"));
Visual Studioはテスト時に速度も出してくれるので、それを参照した。 すると、意外や意外、2番の方が圧倒的に早かった。 1番は2~3ミリ秒、2番は1ミリ秒以下。 文字をバイト配列へ変換する辺りで時間食ってるんだろうか? 漢字とかは1番を使わざるを得ないけれど、ひらがなやカタカナ程度であれば2番のやり方の方が良い様だ。 もしかしたら、僕のやり方がヘボいだけで1番の方がやはり早い場合もあるのかも知れないが。
となると…… ひらがな<>カタカナの相互変換とかだとどうなるのか。 昔、全角と半角の相互変換では長大なswich文を書いた事がある。ガとか出てくると、ビットシフトじゃ対応しきれないからだ。 でも、全角同士の変換であれば問題はない。というかまあ、全角半角でも面倒くさがらずにちゃんとコードを書けば行けるだろうし。 また今度、機会があったら試してみよう。