简短回答:
文件系统对象使用与系统区域设置相关联的代码页将"Unicode"映射到"ASCII"。(Chr和ChrW使用用户区域设置。)
应用:
系统代码页和线程(用户)代码页之间可能存在静默转位错误。如果代码页中缺少代码点,或者像日语和UTF-8一样,代码页包含多字节字符,则可能会出现编码和解码错误。
VBScript没有本地方法来检测用户、线程或系统代码页。可以从通过SetLocale设置的区域设置或由GetLocale返回的线程(用户)代码页推断出来(这里有一个列表: https://www.science.co.il/language/Locale-codes.php),但是似乎没有任何MS文档。在Win2K+上,可以使用WMI查询系统代码页。CHCP命令查询和更改OEM代码页,它既不是用户代码页也不是系统代码页。
系统代码页可能会被应用程序清单欺骗。除非创建具有新清单的新进程或更改注册表后重新启动系统,否则应用程序(如cscript或wscript)或脚本(如VBScript或JScript)无法更改其父级系统。
s = chr(i)
'creates a Unicode string, using the Thread Locale Codepage.
不存在的字符编码点将被映射为控制字符:127 变成 U+00FF(一个标准的Unicode控制字符),128 变成 U+20AC(欧元符号)而 129 变成 0081(这是一个Unicode控制字符区域中的编码点)。在VBScript中,线程区域设置可以通过SetLocale和GetLocale进行设置和读取。
createobject("Scripting.FileSystemObject").OpenTextFile(strOutFile, 2, True).write s
'creates a 'code page' string, using the System Locale Codepage.
有两种方法可以处理Windows无法映射的Unicode值:它可以映射到默认字符,或返回错误。 "Scripting.FileSystemObject"使用错误设置,并抛出异常。
更详细地说,线程区域设置默认情况下是用户区域设置,即“区域和语言”控制面板小程序中的日期和时间格式设置(在不同版本的Windows中称为不同的名称)。它有一个关联的代码页。根据MS国际化专家Michka(Michael Kaplan,已故)的说法,它具有代码页是为了使月份和星期几可以用适当的字符编写,并且不应用于任何其他目的。
ASP经典人员显然有其他想法,因为Response.CodePage是线程区域设置,并且可以通过vbscript GetLocale和SetLocale等方法进行控制。如果更改了用户区域设置,则会通知所有进程,并更新使用默认值的任何线程。(我没有测试当前使用非默认值的线程会发生什么)。
系统区域设置也称为“非 Unicode 程序的语言”,可以在“区域和语言”应用程序中找到,但需要重新启动才能更改。这是 Windows(“系统”)内部用于映射“A” API 和“W” API 之间的值。更改此设置不会影响 Windows GUI 的语言(即
不是“非 Unicode 程序”)。
假设“时间和日期”设置与“非 Unicode 程序的语言”匹配,任何可以创建有效 Unicode 代码点的 Chr(i) 都将从 Unicode 精确地映射回“代码页”。请注意,对于“控制字符”,此方法也适用:还要注意,它不可逆转:UTF-CodePage-UTF 并不总是完全往返。众所周知(字符、修饰符)-CodePage-(复杂字符)无法正确往返,其中 Unicode 定义了构造语言字符表示的多种方式。
如果"时间和日期"与"非Unicode程序的语言"不匹配,就会出现任何翻译问题,例如U+0101在cp28594上是0xE0,在cp28603上是0xE2:Chr(224)会通过U+0101进行处理,并写成226。
即使没有转置错误,如果"时间和日期"与"非Unicode程序的语言"不匹配,则在翻译为系统区域设置时程序可能会失败:如果Unicode代码点没有匹配的代码页代码点,则FileSystemObject将引发异常。
Chr(i)可能存在映射错误,从代码页到Unicode。 代码页1041(日语)是一个双字节代码页(可能是Shift JIS)。0x81仅是双字节对的第一个字节。为了与其他代码页面保持一致,0x81应映射到控制字符0081,但在给定81和代码页1041时,Windows假定缓冲区或BSTR中的下一个字节是双字节对的第二个字节(我还没有确定转换之前或之后是否出现错误)。 Chr(& amp; H81)被映射到U + xx81(81,xx)。当我这样做时,我得到了U + 4581,这是一个CJK统一表意符号(紫色水鱼草):它不被代码页1041映射。
Chr(1)处的映射错误不会导致VBScript异常发生在创建点。如果创建的UTF-16代码点无效或不在系统区域设置代码页上,将在.write处发生FileSystemObject异常。通过使用ChrW(i)而不是Chr(i),可以避免这种特定问题。在代码页1041上,ChrW(129)变成Unicode控制字符0081,而不是xx81。
背景:
程序可以使用任何已安装的代码页映射Unicode和“codepage”:Windows函数MultiByteToWideChar和WideCharToMultiByte将[UINT CodePage]作为第一个参数。该机制在Windows内部用于将“A”API映射到“W”API,例如GetAddressByNameA和GetAddressByNameW。Windows在内部是“W”(宽,16位),并且在调用时将“A”字符串映射到“W”字符串,并在返回时从“W”映射回“A”。当Windows进行映射时,它使用与“系统区域设置”关联的代码页,也称为“非Unicode程序的语言”。
Windows API函数WriteFile写入字节而不是字符,因此它不是“A”或“W”函数。使用它的任何程序都必须处理字符串和字节之间的转换。c函数fwrite写入字符,因此它可以处理16位字符,但它无法处理像UTF-8或UTF-16这样的可变长度码点:同样,使用“fwrite”的任何程序都必须处理字符串和单词之间的转换。
C++函数
fwrite可以处理UTF格式,而编译器函数
_fwrite则根据编译器的不同而有所不同。在Windows上,如果需要进行代码页转换,则使用MultiByteToWideChar和WideCharToMultiByte API。 "A"代码页和"A" API被称为"ANSI"或"ASCII"或"OEM",最初是8位字符,然后发展为双字节字符,现在已经发展为UTF-8(1..3个字节)。 "W" API最初是16位字符,然后发展为UTF-16(1..6个字节)。两者都是多字节字符编码:区别在于对于"A" API和代码页,字长为8位:对于"W" API和UTF-16,字长为16位。由于它们都是多字节映射,并且因为“byte”、“word”、“char”和“character”在不同的上下文中意义不同,以及因为“A”和特别是“W”与多年前的含义不同,我只是使用“A”和“W”和“code page”和“Unicode”。
"OEM"是与另一个语言环境相关联的代码页:控制台I/O API。它是每个进程的(它是一个线程区域设置),可以动态更改(使用CHCP命令),其默认值在安装时设置:没有提供GUI来更改存储在注册表中的值。大多数控制台程序不使用控制台I/O API,并且如所写,使用系统语言环境、用户语言环境或两者混合(有时是无意中)。系统语言环境可以通过使用“清单”进行欺骗,并且有一个名为“AppLocale”的WinXP实用程序也可以做到这一点。"