Unicode的问题
需要注意的是,
Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。
比如,汉字“严”的unicode是十六进制数4E25,转换成二进制数足足有15位(100111000100101),也就是说这个符号的表示至少需要2个字节。表示其他更大的符号,可能需要3个字节或者4个字节,甚至更多。
这里就有两个严重的问题,
第一个问题是,如何才能区别unicode和ascii?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果unicode统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。
它们造成的结果是:1)
出现了unicode的多种存储方式,也就是说有许多种不同的二进制格式(utf-8,gbk),可以用来表示unicode。2)unicode在很长一段时间内无法推广,直到互联网的出现。
Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
下面,还是以汉字“严”为例,演示如何实现UTF-8编码。
已知“严”的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800-0000 FFFF),因此“严”的UTF-8编码需要三个字节,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。然后,从“严”的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,“严”的UTF-8编码是“11100100 10111000 10100101”,转换成十六进制就是E4B8A5。
================================================================
首先,要搞清楚 code point 和 encoding 的区别。Java 是遵循 unicode 4.0 标准的,而内部的 character 以 utf-16 作为 encoding。unicode 4.0 标准包含从 U+0000-U+FFFF 的基本多语言平面和 U+10000-U+10FFFF 的扩展平面的文字,这是 code point。Java 的 char 类型是 16 bit 的,所以单个 char 只支持基本平面内的文字,而扩展平面的文字是由一对 char 来表示的。
而 String.getBytes() 这个方法是按照指定的 encoding 返回字符串,一般中文系统的默认编码是 utf-8 (linux, mac) 或者 gbk/gb18030 (windows)。只要是基本平面内的文字,utf-8码的中文都是3字节的,而 gbk/gbk18030 是2字节的。
================================================================
char c='你';
System.out.print(Integer.toHexString(c));
System.out.println(" "+Integer.toBinaryString(c));
String s=Character.toString(c);
//用utf-8进行编码后的字节数组内容
for(byte b:s.getBytes("utf-8")){
System.out.print(Integer.toHexString(b));
System.out.println(" "+Integer.toBinaryString(b));
}
System.out.println("---------------");
//用gb2312进行编码后的字节数组内容
byte[] gbb = new String(s.getBytes("utf-8"),"utf-8").getBytes("gb2312");
for(byte b:gbb){
System.out.print(Integer.toHexString(b));
System.out.println(" "+Integer.toBinaryString(b));
}
//从Unicode转化为byte[]
s = new String(gbb,"gb2312");//由于gbb字节数组是经过gb2312编码,必须先解码还原成为Unicode
ByteBuffer byteBuffer = ByteBuffer.allocate(6);
CharBuffer charBuffer = byteBuffer.asCharBuffer();
charBuffer.put(s);
//用asCharBuffer()方法创建的视图与原buffer的位置、界限和标记值是相互独立的
//例如这里,byteBuffer.position()==0,所以要先设置position再flip,
byteBuffer.position(charBuffer.position()*2);
System.out.println(byteBuffer);
byteBuffer.flip();
System.out.println(byteBuffer);
System.out.println(charBuffer.flip());
while(byteBuffer.hasRemaining()){
byte b = byteBuffer.get();
System.out.print(Integer.toHexString(b));
System.out.println(" "+Integer.toBinaryString(b));
}
输出如下:
4f60 100111101100000
ffe4 11111111111111111111111111100100
ffbd 11111111111111111111111110111101
ffa0 11111111111111111111111110100000
---------------
ffffffc4 11111111111111111111111111000100
ffffffe3 11111111111111111111111111100011
java.nio.HeapByteBuffer[pos=2 lim=6 cap=6]
java.nio.HeapByteBuffer[pos=0 lim=2 cap=6]
你
4f 1001111
60 1100000
ByteBuffer的asCharBuffer方法
asCharBuffer
public abstract CharBuffer asCharBuffer()创建此字节缓冲区的视图,作为 char 缓冲区。
新缓冲区的内容将从此缓冲区的当前位置开始。此缓冲区内容的更改在新缓冲区中是可见的,反之亦然;这两个缓冲区的位置、界限和标记值是相互独立的。
新缓冲区的位置将为零,其容量和界限将为此缓冲区中所剩余的字节数的二分之一,其标记是不确定的。当且仅当此缓冲区为直接时,新缓冲区才是直接的,当且仅当此缓冲区为只读时,新缓冲区才是只读的。
返回:
新的 char 缓冲区
分享到:
相关推荐
总的来说,按照字节长度截取字符串需要考虑字符编码的影响,通过`Encoding`类处理字符串的字节表示,并结合正则表达式进行精确截取。在实际应用中,确保对字符串编码的理解和处理方式的正确性至关重要,以避免可能...
与此相反,多字节字符串通常是基于ANSI编码(如ASCII或GBK),其中每个字符可能占用1到多个字节。 在Win32 API中,函数通常有两种形式:一种接受Unicode字符串(以`W`结尾),另一种接受多字节字符串(以`A`结尾)...
你可以通过运行这个程序,观察输入图片文件和输出的字符串,理解二进制字节与字符串之间的转换过程。同时,也可以通过反向转换验证数据是否能准确还原,确保图片的质量和完整性不受影响。 总之,理解和掌握二进制...
特别是在涉及到文本显示、格式化或解析时,了解字符串中单字节字符和双字节字符的数量是至关重要的。单字节字符通常指的是ASCII字符,而双字节字符则涉及到Unicode字符集,如汉字和其他非英文字符。下面将详细探讨...
注意,由于字符可能由多个字节组成(如UTF-8编码中的多字节字符),因此截取字节时可能会截断字符。为了确保完整性,通常需要以字符边界进行截取,这可能需要借助于`codecs`库的`decode()`和`iterdecode()`等方法。 ...
web应用中,客户端和服务器端需要交换信息,字符串形式的信息交互是...如果字符串中有中文,客户端在信息发送前需要把它转换为字节数组,转换的时候需要采用指定的编码。 本文提供的方法不需要指定编码,是通用的方法。
// 将字符串转换为字节数组,指定旧的字符集 byte[] bs = str.getBytes(oldCharset); // 使用新的字符集重新构造字符串 return new String(bs, newCharset); } return null; } ``` 通过上述方法,我们可以...
总的来说,处理带有汉字的字符串时,按照字节截取需要考虑字符编码,以避免破坏字符完整性。通过自定义方法并结合Java的字符编码功能,我们可以有效地解决这个问题。在实际开发中,理解字符编码和字节流的概念对于...
在实际应用中,字节数组和字符串的转换通常与文件操作结合。例如,读取二进制文件到字节数组,然后转换成字符串;或者将字符串转换成字节数组,写入二进制文件。 示例: ```vb ' 读取二进制文件到字节数组 Open ...
在C#中,我们可以使用`System.Convert`类的`ToBase64String`方法将普通字符串(UTF-8编码的字节数组)转换为Base64字符串。首先,我们需要将字符串转换为字节数组,然后进行编码。 ```csharp string plainText = ...
如果你并不确定编码方式或者数据是二进制的,你最好将字符串编码成字节。 在构造一个对象的时候,Python通常会复制你提供的字符串数据。如果有必要的话,你需要在后面去释放C字符串。同时,为了让程序更加健壮,你...
在LabVIEW中处理字符串,尤其是中文字符串,有时会涉及到特殊的技巧和注意事项,因为中文字符是多字节的,与英文等单字节字符处理方式有所不同。这个"LabVIEW拆分中文字符串.rar"文件很可能是提供了一个解决此类问题...
通过上述分析,我们可以看到,按字节截取字符串并不简单,特别是当涉及到多字节字符编码时。Java代码示例提供了一个相对复杂的解决方案,通过仔细检查字节序列并确保完整字符的边界,有效地实现了这一功能。这对于...
为了将一个字符串转换为十六进制表示,可以先将其编码为字节数组,再将每个字节转换为十六进制形式: ```csharp public static string StringToHexString(string str, Encoding encoding) { byte[] bytes = ...
首先,我们要明白一个基本概念:字符串在计算机内存中是以字节形式存储的,每个字符对应一定的字节数,这取决于字符编码。在ASCII编码中,一个字符通常占用1个字节;而在Unicode编码如UTF-8或UTF-16中,字符可能占用...
在C#编程中,数据传输和...此外,`Convert`类提供了通用的转换方法,如`Convert.ToInt32`、`Convert.ToChar`等,但在处理字节与字符之间的转换时,使用`Encoding`类的方法更为合适,因为它能更好地处理多字节字符编码。
如果字节数组是通过ASCII字符串转换得到的,那么转换回的字符串将与原始ASCII字符串相同,除非字节数组包含非打印的ASCII码。 4. **十六进制表示**:在LabVIEW中,有时需要将字节数组表示为十六进制字符串,这对于...
1. **宽字符与多字节字符**:在Windows API中,Unicode字符串通常被称为宽字符,用W表示,如LPCWSTR类型。而ANSI字符串则称为多字节字符,用A表示,如LPCSTR类型。转换过程通常涉及`MultiByteToWideChar`和`...
这在处理包含多字节字符(如中文或特殊符号)的字符串时尤为重要。 ### 扩展方法的背景与需求 在默认情况下,C#中的`string.Substring`方法是基于字符的,这意味着它会根据字符边界来截取字符串。然而,在处理...
字符编码是将字符与数字(通常为二进制)进行映射的过程,常见的字符编码有ASCII、GB2312、GBK、UTF-8、UTF-16等。这些编码各有特点,例如ASCII只支持英文字符,而UTF-8则广泛支持多语言字符。 C#中的`...