Unicodeの文字が記号かどうか調べる方法

当たり前ですが、Unicodeコンソーシアムでは現時点で定義されている文字にはすべて情報を当てはめています。この内容は公開されているので、その定義ファイルから対象の文字コードを持つ属性を調べればそれが記号かどうかがわかります。例えばカギカッコ(「:0x300C)は「300C;LEFT CORNER BRACKET;Ps;0;ON;;;;;Y;OPENING CORNER BRACKET;;;;」と記述されていています。注目すべきは「Ps」で、これが何を意味するかはファイルフォーマット情報で確認できます。この場合は「L(文字)」や「N(数値)」で始まっていないので、これは文字ではなく記号だとみなすことができます。

これを踏まえてJavascriptで記号かどうか判別するプログラムを作ってみました。UnicodeData.txtをそのまま格納するとコストがかかるので、必要最低限の情報だけ抜き取るプログラムをC#で用意しています。
unicode.cs
static void Main(string[] args)
{
	StreamReader r = File.OpenText(path);

	//0000;<control>;Cc;0;BN;;;;;N;NULL;;;;
	FileStream fs = new FileStream("table.txt", FileMode.Create);
	StreamWriter w = new StreamWriter(fs, Encoding.UTF8);

	bool type_letter = true;
	string line; int total = 0, letter = 0;
	while ((line = r.ReadLine()) != null) {
		total++;
		string[] pms = line.Split(';');
		string cate = pms[2];
		if ((cate[0] == 'L' && cate[1] != 'm') || (cate[0] == 'N' && cate[1] != 'o')) {
			letter++;
			if (type_letter == false) {
				w.Write(Convert.ToInt32(pms[0],16).ToString() + ",");
			}
			type_letter = true;
		} else {
			if (type_letter == true) {
				w.Write(Convert.ToInt32(pms[0], 16).ToString() + ",");
			}
			type_letter = false;
		}
	}
	r.Close();

	w.Flush();
	fs.Close();

	Console.WriteLine(letter.ToString()+"/"+total.ToString());
	Console.ReadLine();
}
結果はこのようになります。
0,48,58,65,91,97,123,170,171,181,182,186,...
これは記号とそうでない文字の開始位置が交互に並んでいます。あとは対象のコードをこの配列から二分探索すればすぐに結果が求まります。
tree.js
var lttable = [0,48,58,65,91,97,...];
function isLetter(n) {
	var left = 0, right = lttable.length - 1, mid;
	while (left <= right) {
		mid = ((left + right) >> 1) | 0;
		var k = n - lttable[mid];
		if (k > 0) {
			left = mid + 1;
		} else {
			right = mid - 1;
		}
	}
	if (lttable[left] > n) left--;
	return ((left % 2) != 0);
}
2013/12/04