上で.NETではUTF-16(.NET Frameworkの標準となるUNICODE文字のエンコード)でBMP領域以外では正確な文字数がとれないみたいなことが書かれていたが、数え方が悪いだけだ。APS.NETの本まで出して何をやっているの。。
弾氏がブログで取り上げたJSの標準関数以外でソロゲートペアに対応した標準関数,ライブライなんてあんまり見たことがない。ま、作らないと行けないってことです。
以下は、私がgistに公開しているサロゲートペアを含む文字列が半角相当何文字になるか調べるサンプル。(SIerっぽいだろう)
using System; | |
using System.Collections.Generic; | |
using System.Text; | |
/* | |
* UNICODEの文字列がJISでのいわゆる半角文字相当で何文字か確認するプログラム。 | |
* | |
* 問題点: | |
* JIS以外の欧州文字(Latain-x)での1バイト文字とか全く気にしていない。 | |
*/ | |
namespace mojicounttest | |
{ | |
class Program | |
{ | |
//http://ash.jp/code/unitbl1.htm より文字コードをは引用した。 | |
static readonly char AsciiStart = ' '; | |
static readonly char AsciiEnd = '}'; | |
static readonly char AsciiTiruda = '~'; | |
static readonly char HalfKatakanaStart = '。'; | |
static readonly char HalfKatakanaEnd = '゚'; | |
static void Main(string[] args) { | |
string text = " 12345アイウエオ 12345あいうえお"; | |
TestChar(text); | |
text = "𠮟る";//𠮟がサロゲートペア文字 | |
TestChar(text); | |
TestCharWithSurrogatePair(text); | |
Console.Read(); | |
} | |
private static void TestChar(string text) { | |
int num = 0; | |
for (int i = 0; i < text.Length; i++) { | |
num += GetHanakuCharCounts(text[i]); | |
} | |
Console.WriteLine("元の文字列:{0}", text); | |
Console.WriteLine("文字数(半角相当): {0}", num); | |
} | |
private static void TestCharWithSurrogatePair(string text) { | |
int num = 0; | |
for (int i = 0; i < text.Length; i++) { | |
if (char.IsSurrogate(text[i])) { | |
num += 2; | |
i++; //次の文字(サロゲートペアのもう一文字)は読み飛ばす | |
continue; | |
} | |
num += GetHanakuCharCounts(text[i]); | |
} | |
Console.WriteLine("元の文字列:{0}", text); | |
Console.WriteLine("文字数(半角相当,サロゲートペア文字は全角1文字でカウント): {0}", num); | |
} | |
static int GetHanakuCharCounts(char c) { | |
if (c >= AsciiStart && c <= AsciiEnd) { | |
return 1; | |
} | |
else if (c == AsciiTiruda) { | |
return 1; | |
} | |
else if (c >= HalfKatakanaStart && c <= HalfKatakanaEnd) { | |
return 1; | |
} | |
else { | |
return 2; | |
} | |
} | |
} | |
} |
この中のTestCharWithSurrogatePair関数で、サロゲートペアを考慮したstringの文字数を調べていている。string型のまま一発で調べる方法なんて無いので、一度char型の配列に分解下後に、char型のstaticメソッドのIsSurrogateを使って、その文字がサロゲートペアの最初の文字か確認して、そうであれば次の文字がもう一つの文字でペアになっているのでchar型二つで1文字とカウントするようにしている。
普通にBCLだけで出来ますね。SIer的にも安心って感じですよ。
これで、UNICODE 6.0にも対応させた文字カウントが出来るのだけど、このままではIVSに対応していない。Windows 7 / 8、IE10以上対応をするには、これにプラスしてIVS対応が必要だ。
と言うことで、気が向いたらそのうちIVSがらみの記事でも書きます。
追記。
ついカッとなって書いたので、元記事の読み込みが正確で無かったです。陳謝してお詫びします。
StringInfo.LengthInTextElementsを使っている例がちゃんとありました。ただ文字数だけ調べたいならこっちの方が便利でしたね。
コメント
RT @ishisaka: .NET FramewrorkでBMP以外のUnicode文字にも対応した文字数の数え方: … http://t.co/1qc8psC2ej
元記事の読み込みが足らなくてスマン買ったです。。
ちなみに、どなたかLengthInTextElementsがIVS含めて文字数返してくれるのかくれないのか知っている方がおられたら教えて下さい