Windows:直接查看cp1252
Windows: directly examine cp1252
让我先声明:我绝不是 Windows 程序员。请帮助我纠正我可能有的任何误解。
我的理解是Windows既有(传统的)单字节字符串接口也有现代化的 Unicode 接口。
我的目标是仔细检查 Windows 内核中实现的 cp1252。我将从 Windows XP 开始,但我计划检查尽可能多的版本。
我打算让这样一个程序的输出格式类似于:https://encoding.spec.whatwg.org/index-windows-1252.txt
我的问题主要是:我将使用哪些 Windows API 函数来完成上述任务?我认为是 mbstowcs_s.
其次:一定要写C才能查看相关接口吗?如果是这样,我会使用什么编译器?我认为 Visual Studio Express 2010 是一个很好的匹配,但我找不到任何(合法)下载它的地方。
对于那些必须知道 X 和 Y 的人来说,cp1252 有两个相互竞争的标准和实现。它们只是略有不同,但确实不同,这对我来说很重要。
WHATWG 规定,所有浏览器都执行此标准:
https://encoding.spec.whatwg.org/index-windows-1252.txt
Microsoft 指定,python 实施此标准:
http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT
区别在于五个不可打印的字符。在 windows 规范中,它们完全未定义,因此这些字节不能通过 cp1252 来回传输。在 WHATWG 规范(和所有浏览器)中,这些字节映射到具有相同值的非打印字符,如在 latin1 中,这意味着这些字节可以通过 cp1252 成功往返。
我强烈怀疑 Microsoft 的实现实际上与 WHATWG 规范和浏览器的实现相匹配,而不是他们发布的规范。这就是我在上面 prove/disprove 所做的。
你的问题没有任何意义。您想要检查从 95 到 10 的每个 Windows 版本使用的 "the encoding"。
但是 Windows 的那些版本中的 none 有 "an encoding"。它们中的每一个都可以以相同的方式配置:它有一个默认的系统编码,由 Microsoft 预先配置,以及一个当前的用户编码,由 Microsoft 或系统 OEM 设置,但用户可以更改。因此,您的测试将不依赖于 Windows 95 与 Windows 7,而是依赖于 Microsoft 的默认设置为 US Windows 95 与 ES Windows 95来自 Microsoft 的默认设置与美国 Windows 95 来自 HP 的默认设置与美国 Windows 来自 Microsoft 的 95 以及控制面板等中的 238 个可能选项中的每一个
此外,要生成您尝试生成的文件类型,您无需接触任何 Win32 API。您需要做的就是调用任何使用配置的系统区域设置字符集的函数,将 single-byte/multi-byte 文本解码为 UTF-16/Unicode 文本。例如,从 C 中,您可以从 MSVCRT 中调用 mbcstowcs
家族之一;从 Python,您可以在 str
(Python 2)/bytes
(Python 3) 对象上调用 decode
方法 sys.getdefaultencoding()
;等等
如果您真的想使用系统界面来测试相同的信息,您可以……但是您会 运行 进入大多数界面的限制。例如,您可以 CreateFileA
创建一个具有 8 位名称的新文件,然后尝试 CreateFileW
以相应的 16 位名称打开同一个文件并验证它是否有效……但是随后您无法测试任何非法文件名字符。
最后,Microsoft 已经 为大多数(如果不是全部的话)这些平台提供了免费的 C 编译器,但是其中一些已经停止服务很久了,所以我不知道你是否能不能(至少合法地)得到它们。但是您始终可以使用 MinGW 来设置基于 gcc 的工具链。不知道现在的版本在Win95上还能不能用,如果不能,老版本应该还是可以的。
要回答你的 X 问题而不是你的 Y 问题:
你真的不能问 "Windows" 如何处理它所谓的 "ANSI strings",因为有多个不同的级别独立处理它们。他们都以兼容的方式这样做是一个很好的赌注……但你的重点是避免那个很好的赌注并直接检查真相。
我认为您可以安全地假设 MultiByteToWideChar
会为您提供与在 Win32 API 中调用 SpamA 和 SpamW 函数相同的结果。 (如果你甚至不能假设,我认为你真的需要测试 API 中的每个函数对以确保它们都有相同的结果......)你可以直接传递 CP_1252
,但我认为在为 1252 配置的系统上传递 CP_OEMCP
可以更好地测试您的要求。或者两者都做。
MSVCRT(处理提供基于 8 位字符串的标准 C 接口和大块 POSIX 给可移植程序,包括 CPython)似乎有其自己的转换。要验证这一点,请致电 mbstowcs
或其亲属之一。
我很确定 Win32 系统层以与用户层相同的方式处理 ANSI 字符串,但您可能想要搜索未记录的 ZwMultiByteToWideChar
或类似的。而且我认为内核不会在任何地方处理 ANSI 字符串——例如,IIRC,当你编写一个文件系统驱动程序时,唯一的路径名接口很宽……但你可能想要下载 DDK 并确保我是对的。
我认为 Explorer GUI shell 依赖 Win32 层来处理所有事情,并且不会在任何地方触及 ANSI 字符串。 cmd.exe 命令行 shell 只处理 Unicode(Win9x 上的 运行 DOS 程序除外)——但它也是一个终端,作为一个终端,它确实实际上处理 ANSI 和 Unicode 字符串并映射它们。特别是,您可以发送 ANSI 或 Unicode 控制台输出并读取 ANSI 或 Unicode 控制台输入。这可能是通过 MultiByteToWideChar
和朋友完成的,但我不能保证。我认为 MSVCRT 的 stdin/out 和 wstdin/out 及其 DOS-conio-style getch/etc. and getwch/etc. functions just access these respective console APIs instead of translating in MSVCRT, but if you don't trust that, you can go around it and either get the native console streams or just call the Console I/O 直接起作用。
那么,如何为这些东西编写测试程序,而不会发现多个不受支持的 Microsoft C++ 编译器版本和每个 OS 的 SDK? (而且,即使您这样做了,您如何确定 WinXP SDK 的更高版本没有对您隐藏 XP 本身存在的问题?)
答案是 LoadLibrary
and GetProcAddress
函数在运行时脱离各自的 DLL。您可以通过为 Windows.
的一个版本编译的程序来执行此操作
或者,甚至更简单,只需使用 Python,并使用其 ctypes
模块访问 DLL 中的函数。只需确保明确创建并传递 LPSTR
和 LPWSTR
缓冲区,而不是在任何地方传递 str
/bytes
/unicode
对象。
所以最终,我认为您只需要一个 20 行的 Python 脚本,该脚本使用 ctypes
从 KERNEL32.DLL
或 [=13= 中调用 MultiByteToWideChar
] 在 MSVCRT32.DLL
或两者中。
在@abernert 的帮助下,我想到了这个。总之,正如我所怀疑的那样,Microsoft 的规范与他们的实现不匹配:
from ctypes import cdll, windll, c_char_p
c = cdll.msvcrt
k = windll.kernel32
LC_ALL = 0 # from locale.h
# reference: https://msdn.microsoft.com/en-US/library/x99tb11d.aspx
c.setlocale.restype = c_char_p
result = c.setlocale(LC_ALL, '.1252')
assert result == 'English_United States.1252', result
from ctypes import create_string_buffer
# cp1252 is classified as "multi-byte" by the msapi along with utf8
mb = create_string_buffer(1)
wc1 = create_string_buffer(2)
wc2 = create_string_buffer(2)
print 'IN | MSVC KERN'
print '---+-----------'
for b in range(0x80, 0xA0):
mb.value = chr(b)
# reference: https://msdn.microsoft.com/en-us/library/yk02bkxb.aspx
result = c.mbtowc(wc1, mb, 1)
assert result == 1, result
# reference:
# https://msdn.microsoft.com/en-us/library/windows/desktop/dd319072.aspx
result = k.MultiByteToWideChar(1252, 0, mb, 1, wc2, 1)
assert result == 1, result
print '%02X | %02X%02X %02X%02X' % (
ord(mb.value),
# little-endian:
ord(wc1.raw[1]), ord(wc1.raw[0]),
ord(wc2.raw[1]), ord(wc2.raw[0]),
)
输出:(在 Windows XP、Vista、7、8.1 上测试)
IN | MSVC KERN
---+-----------
80 | 20AC 20AC
81 | 0081 0081
82 | 201A 201A
83 | 0192 0192
84 | 201E 201E
85 | 2026 2026
86 | 2020 2020
87 | 2021 2021
88 | 02C6 02C6
89 | 2030 2030
8A | 0160 0160
8B | 2039 2039
8C | 0152 0152
8D | 008D 008D
8E | 017D 017D
8F | 008F 008F
90 | 0090 0090
91 | 2018 2018
92 | 2019 2019
93 | 201C 201C
94 | 201D 201D
95 | 2022 2022
96 | 2013 2013
97 | 2014 2014
98 | 02DC 02DC
99 | 2122 2122
9A | 0161 0161
9B | 203A 203A
9C | 0153 0153
9D | 009D 009D
9E | 017E 017E
9F | 0178 0178
将此与 Microsoft 在 unicode.org 注册的 the spec 进行比较:
0x80 0x20AC #EURO SIGN
0x81 #UNDEFINED
0x82 0x201A #SINGLE LOW-9 QUOTATION MARK
0x83 0x0192 #LATIN SMALL LETTER F WITH HOOK
0x84 0x201E #DOUBLE LOW-9 QUOTATION MARK
0x85 0x2026 #HORIZONTAL ELLIPSIS
0x86 0x2020 #DAGGER
0x87 0x2021 #DOUBLE DAGGER
0x88 0x02C6 #MODIFIER LETTER CIRCUMFLEX ACCENT
0x89 0x2030 #PER MILLE SIGN
0x8A 0x0160 #LATIN CAPITAL LETTER S WITH CARON
0x8B 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK
0x8C 0x0152 #LATIN CAPITAL LIGATURE OE
0x8D #UNDEFINED
0x8E 0x017D #LATIN CAPITAL LETTER Z WITH CARON
0x8F #UNDEFINED
0x90 #UNDEFINED
0x91 0x2018 #LEFT SINGLE QUOTATION MARK
0x92 0x2019 #RIGHT SINGLE QUOTATION MARK
0x93 0x201C #LEFT DOUBLE QUOTATION MARK
0x94 0x201D #RIGHT DOUBLE QUOTATION MARK
0x95 0x2022 #BULLET
0x96 0x2013 #EN DASH
0x97 0x2014 #EM DASH
0x98 0x02DC #SMALL TILDE
0x99 0x2122 #TRADE MARK SIGN
0x9A 0x0161 #LATIN SMALL LETTER S WITH CARON
0x9B 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
0x9C 0x0153 #LATIN SMALL LIGATURE OE
0x9D #UNDEFINED
0x9E 0x017E #LATIN SMALL LETTER Z WITH CARON
0x9F 0x0178 #LATIN CAPITAL LETTER Y WITH DIAERESIS
我很清楚标记为 UNDEFINED
的插槽(字节 81 8D 8F 90 和 9D)不是未定义的,不是错误,而是解码为相同序号的不可打印字符,就像它们在 [=16 中所做的那样=], 下面:
0 0x20AC € (EURO SIGN)
1 0x0081 (<control>)
2 0x201A ‚ (SINGLE LOW-9 QUOTATION MARK)
3 0x0192 ƒ (LATIN SMALL LETTER F WITH HOOK)
4 0x201E „ (DOUBLE LOW-9 QUOTATION MARK)
5 0x2026 … (HORIZONTAL ELLIPSIS)
6 0x2020 † (DAGGER)
7 0x2021 ‡ (DOUBLE DAGGER)
8 0x02C6 ˆ (MODIFIER LETTER CIRCUMFLEX ACCENT)
9 0x2030 ‰ (PER MILLE SIGN)
10 0x0160 Š (LATIN CAPITAL LETTER S WITH CARON)
11 0x2039 ‹ (SINGLE LEFT-POINTING ANGLE QUOTATION MARK)
12 0x0152 Œ (LATIN CAPITAL LIGATURE OE)
13 0x008D (<control>)
14 0x017D Ž (LATIN CAPITAL LETTER Z WITH CARON)
15 0x008F (<control>)
16 0x0090 (<control>)
17 0x2018 ‘ (LEFT SINGLE QUOTATION MARK)
18 0x2019 ’ (RIGHT SINGLE QUOTATION MARK)
19 0x201C “ (LEFT DOUBLE QUOTATION MARK)
20 0x201D ” (RIGHT DOUBLE QUOTATION MARK)
21 0x2022 • (BULLET)
22 0x2013 – (EN DASH)
23 0x2014 — (EM DASH)
24 0x02DC ˜ (SMALL TILDE)
25 0x2122 ™ (TRADE MARK SIGN)
26 0x0161 š (LATIN SMALL LETTER S WITH CARON)
27 0x203A › (SINGLE RIGHT-POINTING ANGLE QUOTATION MARK)
28 0x0153 œ (LATIN SMALL LIGATURE OE)
29 0x009D (<control>)
30 0x017E ž (LATIN SMALL LETTER Z WITH CARON)
31 0x0178 Ÿ (LATIN CAPITAL LETTER Y WITH DIAERESIS)
让我先声明:我绝不是 Windows 程序员。请帮助我纠正我可能有的任何误解。
我的理解是Windows既有(传统的)单字节字符串接口也有现代化的 Unicode 接口。
我的目标是仔细检查 Windows 内核中实现的 cp1252。我将从 Windows XP 开始,但我计划检查尽可能多的版本。
我打算让这样一个程序的输出格式类似于:https://encoding.spec.whatwg.org/index-windows-1252.txt
我的问题主要是:我将使用哪些 Windows API 函数来完成上述任务?我认为是 mbstowcs_s.
其次:一定要写C才能查看相关接口吗?如果是这样,我会使用什么编译器?我认为 Visual Studio Express 2010 是一个很好的匹配,但我找不到任何(合法)下载它的地方。
对于那些必须知道 X 和 Y 的人来说,cp1252 有两个相互竞争的标准和实现。它们只是略有不同,但确实不同,这对我来说很重要。
WHATWG 规定,所有浏览器都执行此标准: https://encoding.spec.whatwg.org/index-windows-1252.txt
Microsoft 指定,python 实施此标准: http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT
区别在于五个不可打印的字符。在 windows 规范中,它们完全未定义,因此这些字节不能通过 cp1252 来回传输。在 WHATWG 规范(和所有浏览器)中,这些字节映射到具有相同值的非打印字符,如在 latin1 中,这意味着这些字节可以通过 cp1252 成功往返。
我强烈怀疑 Microsoft 的实现实际上与 WHATWG 规范和浏览器的实现相匹配,而不是他们发布的规范。这就是我在上面 prove/disprove 所做的。
你的问题没有任何意义。您想要检查从 95 到 10 的每个 Windows 版本使用的 "the encoding"。
但是 Windows 的那些版本中的 none 有 "an encoding"。它们中的每一个都可以以相同的方式配置:它有一个默认的系统编码,由 Microsoft 预先配置,以及一个当前的用户编码,由 Microsoft 或系统 OEM 设置,但用户可以更改。因此,您的测试将不依赖于 Windows 95 与 Windows 7,而是依赖于 Microsoft 的默认设置为 US Windows 95 与 ES Windows 95来自 Microsoft 的默认设置与美国 Windows 95 来自 HP 的默认设置与美国 Windows 来自 Microsoft 的 95 以及控制面板等中的 238 个可能选项中的每一个
此外,要生成您尝试生成的文件类型,您无需接触任何 Win32 API。您需要做的就是调用任何使用配置的系统区域设置字符集的函数,将 single-byte/multi-byte 文本解码为 UTF-16/Unicode 文本。例如,从 C 中,您可以从 MSVCRT 中调用 mbcstowcs
家族之一;从 Python,您可以在 str
(Python 2)/bytes
(Python 3) 对象上调用 decode
方法 sys.getdefaultencoding()
;等等
如果您真的想使用系统界面来测试相同的信息,您可以……但是您会 运行 进入大多数界面的限制。例如,您可以 CreateFileA
创建一个具有 8 位名称的新文件,然后尝试 CreateFileW
以相应的 16 位名称打开同一个文件并验证它是否有效……但是随后您无法测试任何非法文件名字符。
最后,Microsoft 已经 为大多数(如果不是全部的话)这些平台提供了免费的 C 编译器,但是其中一些已经停止服务很久了,所以我不知道你是否能不能(至少合法地)得到它们。但是您始终可以使用 MinGW 来设置基于 gcc 的工具链。不知道现在的版本在Win95上还能不能用,如果不能,老版本应该还是可以的。
要回答你的 X 问题而不是你的 Y 问题:
你真的不能问 "Windows" 如何处理它所谓的 "ANSI strings",因为有多个不同的级别独立处理它们。他们都以兼容的方式这样做是一个很好的赌注……但你的重点是避免那个很好的赌注并直接检查真相。
我认为您可以安全地假设 MultiByteToWideChar
会为您提供与在 Win32 API 中调用 SpamA 和 SpamW 函数相同的结果。 (如果你甚至不能假设,我认为你真的需要测试 API 中的每个函数对以确保它们都有相同的结果......)你可以直接传递 CP_1252
,但我认为在为 1252 配置的系统上传递 CP_OEMCP
可以更好地测试您的要求。或者两者都做。
MSVCRT(处理提供基于 8 位字符串的标准 C 接口和大块 POSIX 给可移植程序,包括 CPython)似乎有其自己的转换。要验证这一点,请致电 mbstowcs
或其亲属之一。
我很确定 Win32 系统层以与用户层相同的方式处理 ANSI 字符串,但您可能想要搜索未记录的 ZwMultiByteToWideChar
或类似的。而且我认为内核不会在任何地方处理 ANSI 字符串——例如,IIRC,当你编写一个文件系统驱动程序时,唯一的路径名接口很宽……但你可能想要下载 DDK 并确保我是对的。
我认为 Explorer GUI shell 依赖 Win32 层来处理所有事情,并且不会在任何地方触及 ANSI 字符串。 cmd.exe 命令行 shell 只处理 Unicode(Win9x 上的 运行 DOS 程序除外)——但它也是一个终端,作为一个终端,它确实实际上处理 ANSI 和 Unicode 字符串并映射它们。特别是,您可以发送 ANSI 或 Unicode 控制台输出并读取 ANSI 或 Unicode 控制台输入。这可能是通过 MultiByteToWideChar
和朋友完成的,但我不能保证。我认为 MSVCRT 的 stdin/out 和 wstdin/out 及其 DOS-conio-style getch/etc. and getwch/etc. functions just access these respective console APIs instead of translating in MSVCRT, but if you don't trust that, you can go around it and either get the native console streams or just call the Console I/O 直接起作用。
那么,如何为这些东西编写测试程序,而不会发现多个不受支持的 Microsoft C++ 编译器版本和每个 OS 的 SDK? (而且,即使您这样做了,您如何确定 WinXP SDK 的更高版本没有对您隐藏 XP 本身存在的问题?)
答案是 LoadLibrary
and GetProcAddress
函数在运行时脱离各自的 DLL。您可以通过为 Windows.
或者,甚至更简单,只需使用 Python,并使用其 ctypes
模块访问 DLL 中的函数。只需确保明确创建并传递 LPSTR
和 LPWSTR
缓冲区,而不是在任何地方传递 str
/bytes
/unicode
对象。
所以最终,我认为您只需要一个 20 行的 Python 脚本,该脚本使用 ctypes
从 KERNEL32.DLL
或 [=13= 中调用 MultiByteToWideChar
] 在 MSVCRT32.DLL
或两者中。
在@abernert 的帮助下,我想到了这个。总之,正如我所怀疑的那样,Microsoft 的规范与他们的实现不匹配:
from ctypes import cdll, windll, c_char_p
c = cdll.msvcrt
k = windll.kernel32
LC_ALL = 0 # from locale.h
# reference: https://msdn.microsoft.com/en-US/library/x99tb11d.aspx
c.setlocale.restype = c_char_p
result = c.setlocale(LC_ALL, '.1252')
assert result == 'English_United States.1252', result
from ctypes import create_string_buffer
# cp1252 is classified as "multi-byte" by the msapi along with utf8
mb = create_string_buffer(1)
wc1 = create_string_buffer(2)
wc2 = create_string_buffer(2)
print 'IN | MSVC KERN'
print '---+-----------'
for b in range(0x80, 0xA0):
mb.value = chr(b)
# reference: https://msdn.microsoft.com/en-us/library/yk02bkxb.aspx
result = c.mbtowc(wc1, mb, 1)
assert result == 1, result
# reference:
# https://msdn.microsoft.com/en-us/library/windows/desktop/dd319072.aspx
result = k.MultiByteToWideChar(1252, 0, mb, 1, wc2, 1)
assert result == 1, result
print '%02X | %02X%02X %02X%02X' % (
ord(mb.value),
# little-endian:
ord(wc1.raw[1]), ord(wc1.raw[0]),
ord(wc2.raw[1]), ord(wc2.raw[0]),
)
输出:(在 Windows XP、Vista、7、8.1 上测试)
IN | MSVC KERN
---+-----------
80 | 20AC 20AC
81 | 0081 0081
82 | 201A 201A
83 | 0192 0192
84 | 201E 201E
85 | 2026 2026
86 | 2020 2020
87 | 2021 2021
88 | 02C6 02C6
89 | 2030 2030
8A | 0160 0160
8B | 2039 2039
8C | 0152 0152
8D | 008D 008D
8E | 017D 017D
8F | 008F 008F
90 | 0090 0090
91 | 2018 2018
92 | 2019 2019
93 | 201C 201C
94 | 201D 201D
95 | 2022 2022
96 | 2013 2013
97 | 2014 2014
98 | 02DC 02DC
99 | 2122 2122
9A | 0161 0161
9B | 203A 203A
9C | 0153 0153
9D | 009D 009D
9E | 017E 017E
9F | 0178 0178
将此与 Microsoft 在 unicode.org 注册的 the spec 进行比较:
0x80 0x20AC #EURO SIGN
0x81 #UNDEFINED
0x82 0x201A #SINGLE LOW-9 QUOTATION MARK
0x83 0x0192 #LATIN SMALL LETTER F WITH HOOK
0x84 0x201E #DOUBLE LOW-9 QUOTATION MARK
0x85 0x2026 #HORIZONTAL ELLIPSIS
0x86 0x2020 #DAGGER
0x87 0x2021 #DOUBLE DAGGER
0x88 0x02C6 #MODIFIER LETTER CIRCUMFLEX ACCENT
0x89 0x2030 #PER MILLE SIGN
0x8A 0x0160 #LATIN CAPITAL LETTER S WITH CARON
0x8B 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK
0x8C 0x0152 #LATIN CAPITAL LIGATURE OE
0x8D #UNDEFINED
0x8E 0x017D #LATIN CAPITAL LETTER Z WITH CARON
0x8F #UNDEFINED
0x90 #UNDEFINED
0x91 0x2018 #LEFT SINGLE QUOTATION MARK
0x92 0x2019 #RIGHT SINGLE QUOTATION MARK
0x93 0x201C #LEFT DOUBLE QUOTATION MARK
0x94 0x201D #RIGHT DOUBLE QUOTATION MARK
0x95 0x2022 #BULLET
0x96 0x2013 #EN DASH
0x97 0x2014 #EM DASH
0x98 0x02DC #SMALL TILDE
0x99 0x2122 #TRADE MARK SIGN
0x9A 0x0161 #LATIN SMALL LETTER S WITH CARON
0x9B 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
0x9C 0x0153 #LATIN SMALL LIGATURE OE
0x9D #UNDEFINED
0x9E 0x017E #LATIN SMALL LETTER Z WITH CARON
0x9F 0x0178 #LATIN CAPITAL LETTER Y WITH DIAERESIS
我很清楚标记为 UNDEFINED
的插槽(字节 81 8D 8F 90 和 9D)不是未定义的,不是错误,而是解码为相同序号的不可打印字符,就像它们在 [=16 中所做的那样=], 下面:
0 0x20AC € (EURO SIGN)
1 0x0081 (<control>)
2 0x201A ‚ (SINGLE LOW-9 QUOTATION MARK)
3 0x0192 ƒ (LATIN SMALL LETTER F WITH HOOK)
4 0x201E „ (DOUBLE LOW-9 QUOTATION MARK)
5 0x2026 … (HORIZONTAL ELLIPSIS)
6 0x2020 † (DAGGER)
7 0x2021 ‡ (DOUBLE DAGGER)
8 0x02C6 ˆ (MODIFIER LETTER CIRCUMFLEX ACCENT)
9 0x2030 ‰ (PER MILLE SIGN)
10 0x0160 Š (LATIN CAPITAL LETTER S WITH CARON)
11 0x2039 ‹ (SINGLE LEFT-POINTING ANGLE QUOTATION MARK)
12 0x0152 Œ (LATIN CAPITAL LIGATURE OE)
13 0x008D (<control>)
14 0x017D Ž (LATIN CAPITAL LETTER Z WITH CARON)
15 0x008F (<control>)
16 0x0090 (<control>)
17 0x2018 ‘ (LEFT SINGLE QUOTATION MARK)
18 0x2019 ’ (RIGHT SINGLE QUOTATION MARK)
19 0x201C “ (LEFT DOUBLE QUOTATION MARK)
20 0x201D ” (RIGHT DOUBLE QUOTATION MARK)
21 0x2022 • (BULLET)
22 0x2013 – (EN DASH)
23 0x2014 — (EM DASH)
24 0x02DC ˜ (SMALL TILDE)
25 0x2122 ™ (TRADE MARK SIGN)
26 0x0161 š (LATIN SMALL LETTER S WITH CARON)
27 0x203A › (SINGLE RIGHT-POINTING ANGLE QUOTATION MARK)
28 0x0153 œ (LATIN SMALL LIGATURE OE)
29 0x009D (<control>)
30 0x017E ž (LATIN SMALL LETTER Z WITH CARON)
31 0x0178 Ÿ (LATIN CAPITAL LETTER Y WITH DIAERESIS)