(关注数据结构和算法,了解更多新知识)
某公厕分别用中文,英文,日语和韩语写了下面一段提示:向前一小步,文明一大步。这种提示在男厕所基本上是见怪不怪了,但关键是下面还有一段用0和1组成的数字,这又什么意思,难道是给外星人看的?
作为一个程序员能敏锐的感觉到这应该就是上面中文的二进制表示方式,于是我就尝试着把它转化为汉字,看看转换之后对不对。
我们都知道汉字在计算机中存储常见的编码有GB2312,GBK,UTF-8,但仔细观察上面的二进制会发现很多地方出现了连续的3个1,所有大胆猜测应该使用的是UTF-8编码(当然只是猜测)。
猜完之后我们再来验证下,在验证之前我们先要了解下UTF-8的实现原理。UTF-8是一种可变长字符编码,它可以用来表示Unicode标准中的任何字符,而且其编码中的第一个字节仍与ASCII相容,使得原来处理ASCII字符的软件无须或只进行少部分修改后,便可继续使用。
UTF-8通常使用1~4个字节表示字符,怎么确定一个字符占几个字节呢?这就和二进制的表示有关,如果是一个字节,那么最高位就是0,剩下的7个二进制可以表示128个字符,这些字符对应ASCII的128个字符。如果是两个字节会以110开头,三个字节是1110开头……。
0xxxxxxx 一个字节
110xxxxx 10xxxxxx 两个字节
1110xxxx 10xxxxxx 10xxxxxx 三个字节
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 四个字节
两个以上字节的后面每个字节都是以10开头,搞懂了UTF-8的原理我们再来看下公厕的二进制编码,首先他是以1110开头的,所以第一个字符肯定是三个字节,也就是24位(每个字节占8位),我们截取前面24位来转换下。
11100101 10010000 10010001
其中红色部分是标志位,我们把它去掉就变成了0101 010000 010001,这是个二进制,我们把它转化为十六进制就是5411,那么这个数字在unicode字符集中对应的字符是哪个呢,我们转换看下。
通过转换我们发现他就是汉字“向”,所以我们猜测他使用的UTF-8编码是正确的,后面的就不在一个个手动转了,我们使用一段代码把它全部转化下。
JAVA:
private static void toChinese() {
String bits = "11100101100100001001000111100101100010011000110" +
"1111001001011100010000000111001011011000010001111111001" +
"10101011011010010100100000111001101001011010000111111001" +
"10100110001000111011100100101110001000000011100101101001" +
"0010100111111001101010110110100101";
int length = bits.length();
byte[] bytes = new byte[length >> 3];
for (int i = 0; i < length; i += 8) {
String byteString = bits.substring(i, i + 8);
bytes[i >> 3] = (byte) Integer.parseInt(byteString, 2);
}
System.out.println("转换之后的结果:" + new String(bytes));
}
打印的结果如下。