ImageVerifierCode 换一换
格式:DOCX , 页数:28 ,大小:85.41KB ,
资源ID:8791269      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/8791269.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(2字符和字符串处理.docx)为本站会员(b****7)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

2字符和字符串处理.docx

1、2字符和字符串处理第2章 U n i c o d e随着M i c r o s o f t 公司的Wi n d o w s 操作系统在全世界日益广泛的流行,对于软件开发人员来说,将目标瞄准国际上的各个不同市场,已经成为一个越来越重要的问题。美国的软件版本比国际版本提前6 个月推向市场,这曾经是个司空见惯的现象。但是,由于各国对Wi n d o w s 操作系统提供了越来越多的支持,因此就更加容易为国际市场生产各种应用软件,从而缩短了软件的美国版本与国际版本推出的时间间隔。Wi n d o w s 操作系统始终不逾地提供各种支持,以帮助软件开发人员进行应用程序的本地化工作。应用软件可以从各种不同

2、的函数中获得特定国家的信息,并可观察控制面板的设置,以确定用户的首选项。Wi n d o w s 甚至支持不同的字体,以适应应用的需要。之所以将这一章放在本书的开头,是因为考虑到U n i c o d e 是开发任何应用程序时要采用的基本步骤。本书的每一章中几乎都要讲到关于U n i c o d e 的问题,而且书中给出的所有示例应用程序都是“用U n i c o d e 实现的”。如果你为Microsoft Windows 2000 或Microsoft Windows CE 开发应用程序,你应该使用U n i c o d e 进行开发。如果你为Microsoft Windows 98 开发

3、应用程序,你必须对某些问题作出决定。本章也要讲述Windows 98 的有关问题。2.1 字符集软件的本地化要解决的真正问题,实际上就是如何来处理不同的字符集。多年来,许多人一直将文本串作为一系列单字节字符来进行编码,并在结尾处放上一个零。对于我们来说,这已经成了习惯。当调用s t r l e n 函数时,它在以0 结尾的单字节字符数组中返回字符的数目。问题是,有些文字和书写规则(比如日文中的汉字就是个典型的例子)的字符集中的符号太多了,因此单字节(它提供的符号最多不能超过2 5 6 个)是根本不敷使用的。为此出现了双字节字符集(D B C S ),以支持这些文字和书写规则。2.1.1 单字节

4、与双字节字符集在双字节字符集中,字符串中的每个字符可以包含一个字节或包含两个字节。例如,日文中的汉字,如果第一个字符在0 x 8 1 与0 x 9 F 之间,或者在0 x E 0 与0 x F C 之间,那么就必须观察下一个字节,才能确定字符串中的这个完整的字符。使用双字节字符集,对于程序员来说简直是个很大的难题,因为有些字符只有一个字节宽,而有些字符则是两个字节宽。如果只是调用s t r l e n 函数,那么你无法真正了解字符串中究竟有多少字符,它只能告诉你到达结尾的0 之前有多少个字节。A N S I 的C 运行期库中没有配备相应的函数,使你能够对双字节字符集进行操作。但是,Micros

5、oft Visual C+的运行期库却包含许多函数,如_ m b s l e n ,它可以用来操作多字节(既包括单字节也包括双字节)字符串。为了帮助你对D B C S 字符串进行操作,Wi n d o w s 提供了下面的一组帮助函数(见表2 - 1 )。前两个函数CharNext 和Char Prev 允许前向或逆向遍历DBCS 字符串,方法是每次一个字符。第三个函数IsDBCSLeadByte, 在字节返回到一个两字字节符的第一个字节时将返回T R U E 。表2-1 对D B C S 字符串进行操作的帮助函数 函数描述PTSTR CharNext(PCTSTR pszCurrentCha

6、r);返回字符串中的下一个字符的地址PTSTR CharPrev (PCTSTR pszStart,PCTSTR p s z C u r r e n t C h a r);返回字符串中的上一个字符的地址BOOL IsDBCSLeadByteTRUE(BYTE bTestChar);如果该字节是DBCS 字符的第一个字节,则返回 尽管这些函数使得我们对D B C S 的操作更容易,但还需要,一个更好的方法让我们来看看U n i c o d e 。2.1.2 Unicode :宽字节字符集U n i c o d e 是A p p l e 和X e r o x 公司于1 9 8 8 年建立的一个技术

7、标准。1 9 9 1 年,成立了一个集团机构负责U n i c o d e 的开发和推广应用。该集团由A p p l e 、C o m p a q 、H P 、I B M 、M i c r o s o f t 、O r a c l e 、Silicon Graphics, Inc.、S y b a s e 、U n i s y s 和X e r o x 等公司组成(若要了解该集团的全部成员,请通过网址w w w. U n i c o d e . o rg 查找)。该集团负责维护U n i c o d e 标准。U n i c o d e 的完整描述可以参阅A d d i s o n We s

8、l e y 出版的Unicode Standard 一书(该书可以通过网址w w w. U n i c o d e . o rg 订购)。U n i c o d e 提供了一种简单而又一致的表示字符串的方法。U n i c o d e 字符串中的所有字符都是1 6 位的(两个字节)。它没有专门的字节来指明下一个字节是属于同一个字符的组成部分,还是一个新字符。这意味着你只需要对指针进行递增或递减,就可以遍历字符串中的各个字符,不再需要调用C h a r N e x t 、C h a r P r e v 和I s D B C S L e a d B y t e 之类的函数。由于U n i c o

9、d e 用一个1 6 位的值来表示每个字符,因此总共可以得到65 000 个字符,这样,它就能够对世界各国的书面文字中的所有字符进行编码,远远超过了单字节字符集的2 5 6 个字符的数目。目前,已经为阿拉伯文、中文拼音、西里尔字母(俄文)、希腊文、西伯莱文、日文、韩文和拉丁文(英文)字母定义了U n i c o d e 代码点。(代码点是字符集中符号的位置。)这些字符集中还包含了大量的标点符号、数学符号、技术符号、箭头、装饰标志、区分标志和其他许多字符。如果将所有这些字母和符号加在一起,总计约达3 5 0 0 0 个不同的代码点,这样,总计65 000 多个代码点中,大约还有一半可供将来扩充时

10、使用。这65536个字符可以分成不同的区域。表2-2 显示了这样的区域的一部分以及分配给这些区域的字符。表2-2 区域字符 1 6 位代码字符16 位代码字符0 0 0 0 - 0 0 7 FA S C I I0 3 0 0 - 0 3 6 F通用区分标志0 0 8 0 - 0 0 F F拉丁文1 字符0 4 0 0 - 0 4 F F西里尔字母0 1 0 0 - 0 1 7 F欧洲拉丁文0 5 3 0 - 0 5 8 F亚美尼亚文0 1 8 0 - 0 1 F F扩充拉丁文0 5 9 0 - 0 5 F F西伯莱文0 2 5 0 - 0 2 A F标准拼音0 6 0 0 - 0 6 F F阿

11、拉伯文0 2 B 0 - 0 2 F F修改型字母0 9 0 0 - 0 9 7 F梵文目前尚未分配的代码点大约还有29 000 个,不过它们是保留供将来使用的。另外,大约有6 0 0 0 个代码点是保留供个人使用的。2.2 为什么使用Unicode当开发应用程序时,当然应该考虑利用U n i c o d e 的优点。即使现在你不打算对应用程序进行本地化,开发时将U n i c o d e 放在心上,肯定可以简化将来的代码转换工作。此外,U n i c o d e 还具备下列功能: 可以很容易地在不同语言之间进行数据交换。 使你能够分配支持所有语言的单个二进制. e x e 文件或D L L

12、文件。 提高应用程序的运行效率(本章后面还要详细介绍)。2.3 Windows 2000与UnicodeWindows 2000 是使用U n i c o d e 从头进行开发的,用于创建窗口、显示文本、进行字符串操作等的所有核心函数都需要U n i c o d e 字符串。如果调用任何一个Wi n d o w s 函数并给它传递一个A N S I 字符串,那么系统首先要将字符串转换成U n i c o d e ,然后将U n i c o d e 字符串传递给操作系统。如果希望函数返回A N S I 字符串,系统就会首先将U n i c o d e 字符串转换成A N S I 字符串,然后将结

13、果返回给你的应用程序。所有这些转换操作都是在你看不见的情况下发生的。当然,进行这些字符串的转换需要占用系统的时间和内存。例如,如果调用C r e a t e Wi n d o w E x 函数,并传递类名字和窗口标题文本的非U n i c o d e 字符串,那么C r e a t e Wi n d o w E x 必须分配内存块(在你的进程的默认堆中),将非U n i c o d e 字符串转换成U n i c o d e 字符串,并将结果存储在分配到的内存块中,然后调用U n i c o d e 版本的C r e a t e Wi n d o w E x函数。对于用字符串填入缓存的函数来说

14、,系统必须首先将U n i c o d e 字符串转换成非U n i c o d e 字符串,然后你的应用程序才能处理该字符串。由于系统必须执行所有这些转换操作,因此你的应用程序需要更多的内存,并且运行的速度比较慢。通过从头开始用U n i c o d e 来开发应用程序,就能够使你的应用程序更加有效地运行。2.4 Windows 98与UnicodeWindows 98 不是一种全新的操作系统。它继承了1 6 位Wi n d o w s 操作系统的特性,它不是用来处理U n i c o d e 的。如果要增加对U n i c o d e 的支持,其工作量非常大,因此在该产品的特性列表中没有包

15、括这个支持项目。由于这个原因,Windows 98 像它的前任产品一样,几乎都是使用A N S I 字符串来进行所有的内部操作的。仍然可以编写用于处理U n i c o d e 字符和字符串的Wi n d o w s 应用程序,不过,使用Wi n d o w s 函数要难得多。例如,如果想要调用C r e a t e Wi n d o w E x 函数并将A N S I 字符串传递给它,这个调用的速度非常快,不需要从你进程的默认堆栈中分配缓存,也不需要进行字符串转换。但是,如果想要调用C r e a t e Wi n d o w E x 函数并将U n i c o d e 字符串传递给它,就必

16、须明确分配缓存,并调用函数,以便执行从U n i c o d e 到A N S I 字符串的转换操作。然后可以调用C r e a t e Wi n d o w E x ,传递A N S I 字符串。当C r e a t e Wi n d o w E x 函数返回时,就能释放临时缓存。这比使用Windows 2000 上的U n i c o d e 要麻烦得多。本章的后面要介绍如何在Windows 98 下进行这些转换。虽然大多数U n i c o d e 函数在Windows 98 中不起任何作用,但是仍有少数U n i c o d e 函数确实非常有用。这些函数是: E n u m R e

17、s o u r c e L a n g u a g e s WG e t Te x t E x t e n t P o i n t 3 2 WE n u m R e s o u r c e N a m e s WG e t Te x t E x t e n t P o i n t WE n u m R e s o u r c e Ty p e s WL s t r l e n WE x t Te x t O u t WM e s s a g e B o x E xWF i n d R e s o u r c e WM e s s a g e B o x WF i n d R e s o u r

18、 c e E x WTe x t O u t WG e t C h a r Wi d t h WWi d e C h a r To M u l t i B y t eG e t C o m m a n d L i n e WM u l t iBy t e To Wi d e C h a r可惜的是,这些函数中有许多函数在Windows 98 中会出现各种各样的错误。有些函数无法使用某些字体,有些函数会破坏内存堆栈,有些函数会使打印机驱动程序崩溃,等等。如果要使用这些函数,必须对它们进行大量的测试。即使这样,可能仍然无法解决问题。因此必须向用户说明这些情况。2.5 Windows CE与Unic

19、odeWindows CE 操作系统是为小型设备开发的,这些设备的内存很小,并且不带磁盘存储器。你可能认为,由于M i c r o s o f t 公司的主要目标是建立一种尽可能小的操作系统,因此它会使用A N S I 作为自己的字符集。但是M i c r o s o f t 公司并非鼠目寸光,他们懂得,Windows CE 的设备要在世界各地销售,他们希望降低软件开发成本,这样就能更加容易地开发应用程序。为此,Windows CE 本身就是使用U n i c o d e 的一种操作系统。但是,为了使Windows CE 尽量做得小一些,M i c r o s o f t 公司决定完全不支持A

20、NSI Wi n d o w s函数。因此,如果要为Windows CE 开发应用程序,必须懂得U n i c o d e ,并且在整个应用程序中使用U n i c o d e 。2.6 需要注意的问题下面让我们进一步明确一下“M i c r o s o f t 公司对U n i c o d e 支持的情况”: Windows 2000 既支持U n i c o d e ,也支持A N S I ,因此可以为任意一种开发应用程序。 Windows 98 只支持A N S I ,只能为A N S I 开发应用程序。 Windows CE 只支持U n i c o d e ,只能为U n i c o

21、 d e 开发应用程序。虽然M i c r o s o f t 公司试图让软件开发人员能够非常容易地开发在这3 种平台上运行的软件,但是U n i c o d e 与A N S I 之间的差异使得事情变得困难起来,并且这种差异通常是我遇到的最大的问题之一。请不要误解,M i c r o s o f t 公司坚定地支持U n i c o d e ,并且我也坚决鼓励你使用它。不过你应该懂得,你可能遇到一些问题,需要一定的时间来解决这些问题。建议你尽可能使用U n i c o d e 。如果运行Windows 98 ,那么只有在必要时才需转换到A N S I 。不过,还有另一个小问题你应该了解,那就

22、是C O M 。2.7 对COM的简单说明当M i c r o s o f t 公司将C O M 从1 6 位Wi n d o w s 转换成Wi n 3 2 时,公司作出了一个决定,即需要字符串的所有C O M 接口方法都只能接受U n i c o d e 字符串。这是个了不起的决定,因为C O M 通常用于使不同的组件能够互相进行通信,而U n i c o d e 则是传递字符串的最佳手段。如果你为Windows 2000 或Windows CE 开发应用程序,并且也使用C O M ,那么你将会如虎添翼。在你的整个源代码中使用U n i c o d e ,将使与操作系统进行通信和与C O

23、M 对象进行通信的操作变成一件轻而易举的事情。如果你为Windows 98 开发应用程序,并且也使用C O M ,那么将会遇到一些问题。C O M 要求使用U n i c o d e 字符串,而操作系统的大多数函数要求使用A N S I 字符串。那是多么难办的事情啊!我曾经从事过若干个项目的开发,在这些项目中,我编写了许多代码,仅仅是为了来回进行字符串的转换。2.8 如何编写Unicode源代码M i c r o s o f t 公司为U n i c o d e 设计了Windows API ,这样,可以尽量减少对你的代码的影响。实际上,你可以编写单个源代码文件,以便使用或者不使用U n i

24、c o d e 来对它进行编译。只需要定义两个宏(U N I C O D E 和_ U N I C O D E ),就可以修改然后重新编译该源文件。2.8.1 C 运行期库对Unicode的支持为了利用U n i c o d e 字符串,定义了一些数据类型。标准的C 头文件S t r i n g . h 已经作了修改,以便定义一个名字为w c h a r _ t 的数据类型,它是一个U n i c o d e 字符的数据类型: typedef unsigned short wchar_t;例如,如果想要创建一个缓存,用于存放最多为9 9 个字符的U n i c o d e 字符串和一个结尾为零

25、的字符,可以使用下面这个语句: wchar_t szBuffer100;该语句创建了一个由1 0 0 个1 6 位值组成的数组。当然,标准的C 运行期字符串函数,如s t r c p y 、s t r c h r 和s t r c a t 等,只能对A N S I 字符串进行操作,不能正确地处理U n i c o d e 字符串。因此,ANSI C 也拥有一组补充函数。清单2 - 1 显示了一些标准的ANSI C 字符串函数,后面是它们的等价U n i c o d e 函数。 char * strcat(char *,const char *);wchar_t * wcscat(wchar_t

26、 *,const wchar_t *);清单2-1 标准的ANSI C 字符串函数和它们的等价U n i c o d e 函数 char * strchr(const char *,int);wchar_t * wcschr(const wchar_t *,wchar_t);int strcmp(const char *,const char *);int wcscmp(const wchar_t *,const wchar_t *);char * strcpy(char *,const char *);wchar_t * wcscpy(wchar_t *,const wchar_t *);s

27、ize_t strlen(const char *);size_t wcslen(const wchar_t *);请注意,所有的U n i c o d e 函数均以w c s 开头,w c s 是宽字符串的英文缩写。若要调用U n i c o d e函数,只需用前缀w c s 来取代A N S I 字符串函数的前缀s t r 即可。注意大多数软件开发人员可能已经不记得这样一个非常重要的问题了,那就是M i c r o s o f t 公司提供的C 运行期库与A N S I 的标准C 运行期库是一致的。ANSI C 规定,C运行期库支持U n i c o d e 字符和字符串。这意味着始终都可

28、以调用C 运行期函数,以便对U n i c o d e 字符和字符串进行操作,即使是在Windows 98 上运行,也可以调用这些函数。换句话说,w c s c a t 、w c s l e n 和w c s t o k 等函数都能够在Windows 98 上很好地运行,这些都是必须关心的操作系统函数。对于包含了对s t r 函数或w c s 函数进行显式调用的代码来说,无法非常容易地同时为A N S I 和U n i c o d e 对这些代码进行编译。本章前面说过,可以创建同时为A N S I 和U n i c o d e 进行编译的单个源代码文件。若要建立双重功能,必须包含T C h a

29、 r. h 文件,而不是包含S t r i n g . h 文件。T C h a r. h 文件的唯一作用是帮助创建A N S I / U n i c o d e 通用源代码文件。它包含你应该用在源代码中的一组宏,而不应该直接调用s t r 函数或者w c s 函数。如果在编译源代码文件时定义了U N I C O D E ,这些宏就会引用w c s 这组函数。如果没有定义_ U N I C O D E ,那么这些宏将引用s t r这组宏。例如,在T C h a r. h 中有一个宏称为_ t c s c p y 。如果在包含该头文件时没有定义_ U N I C O D E ,那么_ t c s

30、 c p y 就会扩展为A N S I 的s t r c p y 函数。但是如果定义了_UNICODE, _tcscpy 将扩展为U n i c o d e的w c s c p y 函数。拥有字符串参数的所有C 运行期函数都在T C h a r. h 文件中定义了一个通用宏。如果使用通用宏,而不是A N S I / U n i c o d e 的特定函数名,就能够顺利地创建可以为A N S I 或U n i c o d e进行编译的源代码。但是,除了使用这些宏之外,还有一些操作是必须进行的。T C h a r. h 文件包含了另外一些宏.若要定义一个A N S I / U n i c o d

31、e 通用的字符串数组,请使用下面的T C H A R 数据类型。如果定义了_ U N I C O D E ,T C H A R 将声明为下面的形式: typedef wchar_t TCHAR;如果没有定义_ U N I C O D E ,则T C H A R 将声明为下面的形式: typedef char TCHAR;使用该数据类型,可以像下面这样分配一个字符串: TCHAR szString100;也可以创建对字符串的指针: TCHAR *szError=Error;不过上面这行代码存在一个问题。按照默认设置,M i c r o s o f t 公司的C + +编译器能够编译所有的字符串,

32、就像它们是A N S I 字符串,而不是U n i c o d e 字符串。因此,如果没有定义_ U N I C O D E ,该编译器将能正确地编译这一行代码。但是,如果定义了_ U N I C O D E ,就会产生一个错误。若要生成一个U n i c o d e 字符串而不是A N S I 字符串,必须将该代码行改写为下面的样子: TCHAR *szError=LError;字符串(literal string )前面的大写字母L ,用于告诉编译器该字符串应该作为U n i c o d e 字符串来编译。当编译器将字符串置于程序的数据部分中时,它在每个字符之间分散插入零字节。这种变更带来的问题是,现在只有当定义了_ U N I C O D E 时,程序才能成功地进行编译。我们需要另一个宏,以便有选择地在字符串

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1