浅谈Windows系统的字符集

本文详细介绍了Windows编程中字符集的重要性,包括Unicode编码标准、CodePage的历史及其在Windows系统中的应用,以及在不同字符集间转换时的注意事项。
摘要由CSDN通过智能技术生成

        我们在Windows环境编程涉及到字符串数据时很有必要对Windows环境各种编码进行了解,以求最大限度地避免系统崩溃、信息丢失的情况发生。现在我将学习过程中的一点笔记与大家分享一下,知道大体脉络后便可有针对性地参考微软官方文档。

        字符在计算机内部该如何表示曾是长期困扰计算机工业界的难题。最初各大计算机公司都用自己定义的约定和字符表来表示字符和符号,这使得计算机间的互操作变得棘手;尤其当对表达更多符号以及非拉丁文的需求不断增加,这种情况愈发严重。而随着各种协议、标准的制定和发展,如今所有的字符集都会属于两大家族中的一个:Unicode和传统字符集(Code Page,码页),即世界上所有基于字符的数据都是用Unicode或传统字符集组成的。

        Windows通过Unicode和一系列的传统字符集(Character Set)对国际市场上众多的书写语言提供支持。

字符集(Character Set)

        字符集是指一个由字符到表示它的数值的映射关系。当今在计算机领域应用最广泛的字符集是Unicode——一个用于字符编码的全球标准。

Unicode

        Unicode,即ISO/IEC10646,是一种适用于全球范围的字符编码标准,它以唯一的数值来代表现代计算所用到的每一个字符。这是一个庞大而复杂的字符集,它致力于囊括人类使用的所有字符和符号,甚至包括楔形文字、象形文字、表情符号等,在通用性方面具有巨大优势。Unicode 13.0版本(发布于2020年3月)定义了143,849个字符,而根据其定义的规范,它最多可以定义1,112,064个字符。另外,Unicode远不只是一个字符集,它还定义了方向性文本(从左向右读,或从右向左读)的处理方式、将字符图形(glyph)绑定到字符集的方式、核对字符串的方法,以及组合、拆解字符的方法等。

        Unicode是XML、ECMASCRIPT(JavaScript)等现代技术所必需的,也是实现ISO/IEC10646标准的官方机制,许多操作系统、所有的现代浏览器,还有大量其他产品都支持Unicode,新编写的Windows应用程序也应该使用Unicode,以避免因涉及多个码页而引起字符表达的不一致问题,同时为应用程序的本地化(localization)提供方便。

        Windows已经支持Unicode很久了,Windows 3.x,Windows 95,Windows NT都有一个DLL负责处理UCS-2(Unicode的一个子集,限于BMP),Windows XP及后续版本应用程序内部采用UTF16-LE。

        Unicode采用16位无符号数表示字符,最多可表示65536(64K)个字符。后来Unicode标准又增加了16个附加的方案,每个都是64K的规模,连同最初那64K,共17组16位编码方案,共1,114,112个可用编码(216×17),范围为U+0000-U+10FFFF。最初的64K叫做BMP(Basic Multilingual Plane),BMP范围之外的字符叫做补充字符。

0000—— FFFFBMP
10000——1FFFF
20000——2FFFF
 … …
100000——10FFFF

        大多数字符由两字节表示,一些较少用到的补充性字符用代理对机制表示。位于U+D800——U+DFFF范围的数值被保留用作“代理对(Surrogate Pair)”,它是一种双字节码,用于支持补充性字符。“代理对”中的第一个(高位)“代理”是U+D800——U+DBFF间的16位值,第二个(低位)“代理”是U+DC00——U+DFFF之间的16位值,这两组数值的组合可支持对补充字符的访问。

Code Page

        传统字符集是Unicode出现之前使用的字符编码标准,比如Windows码页(Windows Code Page),它用单个8位代码值或几个8位代码的组合来表示特定语言的字符。

        Code Page(码页)简单地说就是一个表格,它将N个(通常是256个,即8比特表达的数值范围)字符映射到用来表示它们的数值。在大多数的码页中,每个字符用一个8比特字节表示。由于表达的范围有限,码页间会存在兼容问题,这使得人们需要先知道或猜测所接收到的文件是用哪个码页编制的,才能对其进行正确处理。为了克服这一局限性,更多的经扩展的码页被设计出来,它们使用非固定宽度的编码来指代字符,即MBCS(Multi-byte Character Set)编码。

        尽管推荐新的Windows应用程序使用Unicode,有些旧的应用程序仍要使用传统的、基于码页的字符集,即使新应用程序在以下情况下也会与码页交互:

        - 与旧应用程序通信

        - 与旧的、不支持Unicode的邮件或新闻组服务器通信

        - 与Windows主控台(Console)通信。其实Windows主控台支持Unicode,但有些旧命令行程序不支持。

        每个码页都有与之对应的标识符,比如1252是英语码页的标识符,936是中文码页GB2312的标识符,该标识符可用于Windows提供的字符集函数。Windows支持的完成的码页清单见 https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers 。

        在诸多码页中我们比较常见的是Windows码页和OEM码页。Windows码页(Windows Code Page或ANSI Code Page)源于早期Windows系统的编码标准,基于美国国家标准(ANSI)草案,最初用于英语及其他西欧语言,后来被确定为ISO8859-1标准,绝大部分与1252字符集相同。用8位代码表示字符,0-127的值保留给ASCII字符,127以上的值表示国际字符。

        OEM码页最初用于MS-DOS,现在仍用于控制台应用,还用于FAT12、FAT16、FAT32文件系统的非扩展文件名。在OEM码页中,127以上的数值用来表示画线和标点字符。

        不论是Windows码页还是OEM码页,0x00-0x7F的值都用于7比特的ASCII字符集,其中0x00-0x19以及0x7F表示标准控制字符,0x20-0x7E表示标准可打印字符,0x80-0xFF则因码页而异。每个码页包含不同的字符,通常是针对一种或一组语言。

        除了Windows码页和OEM码页外,应用程序还可能用到非Windows原生的码页,比如EBCDIC以及苹果Macintosh码页。

        Unicode与码页也有交集。Unicode的两种编码UTF-7和UTF-8是以码页的形式实现的,与其他码页一样,它们也有对应的数字标识符(分别是65000和65001)。

        码页可能是单字节字符集(SBCS-Single-Byte Character Set)或双字节字符集(DBCS-Double-Byte Character Set)。单字节字符集是指将256个字符对应到表示它们的数值的映射,并将这种映射实现位码页。在单字节字符集中,一个字符用一个字节表示,最多可以表示256个字符。双字节字符集也叫扩展的8位字符集(Extended 8-bit Character Set),主要用于表示中文、日文等亚洲语言,在这种码页中,有些字符,比如数字和英文字符,用单字节码表示,其他字符,如中文汉字、日语字符等,以双字节表示,第一个字节数值大于127,称为前导字节(Lead Byte),第二个字节称为尾字节(Tail Byte)。前导字节必须结合尾字节才能代表一个字符。

        要解析一个DBCS字符串,必须从头开始向前扫描。如果遇到一个前导字节,就要将其后的字节作为尾字节,这两个字节代表一个字符。在DBCS字符串做子串的查找要比SBCS字符串复杂得多,支持DBCS的应用程序必须使用特殊的函数,如_mbsstr。

        一些旧协议会要求使用SBCS或DBCS码页。每种码页支持的字符集不同,编码方式也有差异,没有一种码页可以支持Unicode所支持的所有字符。

        除了SBCS和DBCS码页,应用程序还可使用多字节字符集(MBCS-Multi-Byte Character Set)码页,如52936,54936,51949,5022X等,这都是用于中文、日文、韩文的码页。这些码页采用与双字节码页相近的编码方式,但某些编码是超越双字节码页编码方式的。

格式转换

        Windows系统提供了字符集函数,用于将基于字符的数据从其原字符集转换成Unicode格式,或转换成另一种传统字符集格式,这些字符集函数还可以用来帮助应用程序创建可用于不支持Unicode的系统的字符数据。本文只做粗略介绍,详情请参考微软官方文档。

        许多Windows API有"A"(ANSI)和"W"(Wide Cha,Unicode)两个版本,'A'版本处理基于Windows码页的文本,'W'版本处理Unicode文本。Windows码页有时也被称作“活动码页”(Active Code Page)或“系统活动码页”(System Active Code Page)。Windows系统总是有一个当前处于活动状态的码页,所有ANSI版的API使用当前活动码页。

        要识别一个DBCS码页,可使用GetCPInfo或GetCPInfoEx函数;IsDBCSLeadByte函数可确定一个值是否可用作双字节字符的引导字符;应用程序可用MultiByteToWideChar()和WideChartoMultiByte在Unicode和DBCS、SBCS间转换。

        在进行字符格式的转换时必须注意一下几点:

                - 将字符在不同码页间转换可能导致崩溃,因为同一个数值在不同码页中可能有不同的涵义。

                - 将字符从Unicode转换到某种码页可能会导致信息丢失,因为一个给定的码页可能不足以表达被转换的Unicode字符串中的所有字符。在使用WideCharToMultiByte函数时要注意这一点。

                - 可以用标准C运行库函数进行Windows码页和OEM码页间的转换,但也要注意二者的差异所造成的信息丢失问题。

   以上是我在学习过程中对Windows下使用的字符集的一点粗浅认识,希望能帮到大家。

  • 23
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值