0%

计算字符串占用的字节长度

计算字符串占用的字节长度

前提

需要了解字符的编码规则.使用不同的编码规则会得到不同的结果.

API

- (NSUInteger)lengthOfBytesUsingEncoding:(NSStringEncoding)enc; // Result in O(n) time; the result is exact. Returns 0 on error (cannot convert to specified encoding, or overflow)

示例

1
2
3
4
5
NSString *chString = @"中国abc";
NSUInteger utf8Bytes = [chString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"utf8Bytes:%ld", utf8Bytes); //9
NSUInteger unicodeBytes = [chString lengthOfBytesUsingEncoding:NSUnicodeStringEncoding];
NSLog(@"unicodeBytes:%ld", unicodeBytes); //10

天朝目前强制使用的是GB18030.

CFStringEncodingExt.h里面包含了其他编码枚举.如:

1
2
3
kCFStringEncodingGB_2312_80 = 0x0630,
kCFStringEncodingGBK_95 = 0x0631, /* annex to GB 13000-93; for Windows 95 */
kCFStringEncodingGB_18030_2000 = 0x0632,

使用:

1
2
NSStringEncoding GBEncoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
NSUInteger gbBytes = [chString lengthOfBytesUsingEncoding: GBEncoding]; //7
1
2
Printing description of gbCodeChData:
<d6d0b9fa 616263>

注意:将字符串转换为NSData,再获取NSData的length,在使用Unicode编码时它会不等于使用lengthOfBytesUsingEncoding获取到的值.主要是由于大端和小端导致的.Unicode 规范定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做”零宽度非换行空格”(zero width no-break space),用FEFF表示。这正好是两个字节,而且FF比FE大1。如果一个文本文件的头两个字节是FE FF,就表示该文件采用大端方式;如果头两个字节是FF FE,就表示该文件采用小端方式。

1
2
3
4
5
NSData* utf8ChData = [chString dataUsingEncoding:NSUTF8StringEncoding];
NSData* unicodeChData = [chString dataUsingEncoding:NSUnicodeStringEncoding];
NSUInteger utf8ChLength = utf8ChData.length; //9
NSUInteger unicodeChLength = unicodeChData.length; //12.不等于上面的10.这是由于Unicode编码后转为二进制传输时前面要加上FEFF/FFFE这两个字节.
NSLog(@"utf8ChLength:%ld,unicodeChLength:%ld", utf8ChLength, unicodeChLength);

打印如下:

1
2
3
4
5
Printing description of utf8ChData:
<e4b8ade5 9bbd6162 63>

Printing description of unicodeChData:
<fffe2d4e fd566100 62006300>

疑问:

Q1:对于一串编码后得到的二进制数据,接收方如何知道该用哪种方式解码呢?
A1:这就需要发送方和接收方事先确定一种编码方式.这样当接收到一串二进制数据后,接收方就知道该使用哪一种方式进行解码了.有点类似于协议.

Q2:对于UTF-16编码在转为二进制后为啥需要在最前面标记是大端还是小端.为什么UTF-8却没有看到?
A2:涉及到一个BOM(Byte Order Mark)概念.字面意思就是标记字节顺序的.这个标记是可选的,不过UTF8字节是没有顺序的,所以一些厂家就把它用作了另一种用途,用来检测一个字节流是否是UTF-8编码。微软做了这种检测,但有些软件不做这种检测, 而把它当作正常字符处理。微软在自己的UTF-8格式的文本文件之前加上了EF BB BF三个字节, windows上面的notepad等程序就是根据这三个字节来确定一个文本文件是ASCII的还是UTF-8的, 然而这个只是微软暗自作的标记, 其它平台上并没有对UTF-8文本文件做个这样的标记。(这里感觉微软的做法跟BOM的字面意思差的有点远了.)

也就是说一个UTF-8文件可能有BOM,也可能没有BOM,那么怎么区分呢?
三种方法。参考:EF BB BF

  1. 用UltraEdit-32打开文件,切换到十六进制编辑模式,察看文件头部是否有EF BB BF。
  2. 用Dreamweaver打开,察看页面属性,看“包括Unicode签名BOM”前面是否有个勾。
  3. 用Windows的记事本打开,选择 “另存为”,看文件的默认编码是UTF-8还是ANSI,如果是ANSI则不带BOM。

反正,Mac上对于UTF-8编码的是没有看到EF BB BF这样的字样.PC上可能有.之所以UTF-16需要而UTF-8不需要,是由于二者编码规则的不一样.UTF-16就是原始的Unicode编码,所以就涉及到解读顺序的问题.但UTF-8的规则使得它不存在解读顺序的问题.

Q3:对于一个数字字符串”123”,发送方在TCP传输时是先传高位还是先传低位?接收方的存储顺序是怎样的?读取时的顺序又是怎样的?如何测试?
A3:网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian排序方式。

参考:

大端、小端与网络字节序

网络字节序与主机字节序

Q4:对于int整型数字123,在内存中是如何存储的?如何测试?

编码规则

ASCII编码

American Standard Code for Information Interchange,美国信息交换标准代码.ASCII码使用指定的7 位或8 位二进制数组合来表示128 或256 种可能的字符。标准ASCII码也叫基础ASCII码,使用7 位二进制数(剩下的1位二进制为0)来表示所有的大写和小写字母,数字0 到9、标点符号, 以及在美式英语中使用的特殊控制字符

0~31及127(共33个)是控制字符或通信专用字符.它们并没有特定的图形显示,但会依不同的应用程序,而对文本显示有不同的影响.

32~126(共95个)是可显示字符(32是空格),其中48~57为0到9十个阿拉伯数字。
65~90为26个大写英文字母,97~122号为26个小写英文字母,其余为一些标点符号、运算符号等。

ASCII编码还是很好理解的,只需查一下表就完事了.可以记住几个常用的如:0x00(0)为null,空字符;0x20(32)为空格;0x30(48)为数字0;0x41(65)为A;0x61(97)为a.

Unicode编码

世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。

Unicode编码的出现就是为了解决这一问题.它将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,这样乱码问题就解决了。

需要注意的是,Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。

Unicode编码系统可分为编码方式和实现方式两个层次。

Unicode的编码方式

Unicode的编码方式与ISO 10646的通用字符集概念相对应。目前实际应用的统一码版本对应于UCS-2,使用16位的编码空间。也就是每个字符占用2个字节。这样理论上一共最多可以表示2^16(即65536)个字符。基本满足各种语言的使用。实际上当前版本的统一码并未完全使用这16位编码,而是保留了大量空间以作为特殊使用或将来扩展。

可以看到Unicode对汉字支持不怎么好,这也是没办法的, 简体和繁体总共有六七万个汉字,而UCS-2最多能表示65536个,才六万 多个,所以Unicode只能排除一些几乎不用的汉字,好在常用的简体汉字 也不过七千多个,为了能表示所有汉字,Unicode也有UCS-4规范,就是用 4个字节来编码字符.

参考:Unicode编码表

Unicode编码表中的0x4E00-0x9FBF为CJK 统一表意符号 (CJK Unified Ideographs,中日韩统一表意文字).

Unicode的实现方式

Unicode的实现方式不同于编码方式。一个字符的Unicode编码是确定的。但是在实际传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对Unicode编码的实现方式有所不同。Unicode的实现方式称为Unicode转换格式(Unicode Transformation Format,简称为UTF)

UTF-8

UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,又称万国码,由Ken Thompson于1992年创建。现在已经标准化为RFC 3629。UTF-8用1到6个字节编码Unicode字符。

UTF-8与Unicode的关系

UTF-8 是 Unicode 的实现方式之一。

UTF-8编码规则

UTF-8 的编码规则很简单,只有二条:

1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。

2)对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。

GB 2312—1980

《信息交换用汉字编码字符集》是由中国国家标准总局1980年发布,1981年5月1日开始实施的一套国家标准,标准号是GB 2312—1980。
GB2312编码适用于汉字处理、汉字通信等系统之间的信息交换,通行于中国大陆;新加坡等地也采用此编码。中国大陆几乎所有的中文系统和国际化的软件都支持GB2312。

GB 2312的出现,基本满足了汉字的计算机处理需要,它所收录的汉字已经覆盖中国大陆99.75%的使用频率。
对于人名、古汉语等方面出现的罕用字,GB 2312不能处理,这导致了后来GBK及GB 18030汉字字符集的出现。

在使用GB2312的程序中,通常采用EUC储存方法,以便兼容于ASCII。浏览器编码表上的“GB2312”,通常都是指“EUC-CN”表示法。
每个汉字及符号以两个字节来表示。第一个字节称为“高位字节”(也称“区字节)”,第二个字节称为“低位字节”(也称“位字节”)。

其他国标码,参考:国家标准代码

上面这些规定咋也看不懂,暂且先记住对于国标码来说每个汉字及符号以两个字节来表示。其他的方面有空再研究.

参考:字符编码笔记:ASCII,Unicode 和 UTF-8

觉得文章有帮助可以打赏一下哦!