关于unicode中的bmp

最早版本的unicode所允许的值是 U+0000 to U+FFFF

后来unicode扩充了,取值范围变成了U+0000 to U+10FFFF .

原先的
U+0000 to U+FFFF这个集合就称作BMP (Basic Multilingual Plane)

这个集合也是mysql utf8_general字符集所能支持的集合(三个字节); 所以,java在插入文字之前应该过滤掉non-bmp字符。

	public static String removeNonBmpUnicode(String str) {
		if (str == null) {
			return null;
		}

		str = str.replaceAll("[^\\u0000-\\uFFFF]", "");
		return str;
	}

BMP之外的字符集合称为"supplementary characters". 由于Java里每个char都是用16位来表示的,一个supplementary character在java里就要用两个特殊的bmp字符来表示。这类特殊的bmp字符分别称作high-surrogates(\uD800-\uDBFF) 和 low-surrogates(\uDC00-\uDFFF).

要注意的是,把surrogates用在java6的正则中时,得到的结果会让人很意外:

//\ud83d\udd12是一个unicode单字(”锁“的形状)
"\ud83d\udd12".matches("\ud83d\udd12")  == true //这个好理解
"\ud83d\udd12".matches("\\ud83d\\udd12")  == false //为什么?java.util.regex.Pattern的javadoc不是说 \uxxxx和\\uxxxx是等价的吗?
"\ud83d\udd12".matches("\ud83d[\udd12]")  == false //不可思议

"\ud83d".matches("[\\u0000-\\uFFFF]") == true  //符合预期
"\ud83d\udd12".matches("[\\u0000-\\uFFFF]+") == false //为什么?
"\ud83d\udd12".matches("[^\\u0000-\\uFFFF]+") == true // 无语了。。。

说白了,surrogate不遵守普通的正则律。

Leave a Comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.