最早版本的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不遵守普通的正则律。