编码.GetEncoding(437).GetString() 有bug吗?

8
我有一个测试程序如下:
char c = '§';
Debug.WriteLine("c: " + (int)c);

byte b = Encoding.GetEncoding(437).GetBytes("§")[0];
Debug.WriteLine("b: " + b);

char c1 = Encoding.GetEncoding(437).GetString(new byte[] { 21 })[0];
Debug.WriteLine("c1: " + (int)c1);

这将产生以下结果:
c: 167
b: 21
c1: 21

据我所见,在这里,GetBytes运行正确。Unicode的167=> CP437的21
但GetString没有运行
CP437的21 => Unicode的21。这是一个bug还是我的错误?

2
很难说,但是GetBytesGetString两者都返回只有一个元素的数组吗? - Kieren Johnstone
1
@Dani:你确定吗?该字符确实存在并且在CP437中是有效的,应该使用一个字节来表示它。它在Unicode中可能不止一个字节,但在437中不是。请检查链接的维基百科页面以获取21号字符的信息。 - Kieren Johnstone
@Kieren Johnstone - 是的,GetBytes(...)的长度为1,而GetString(...)的长度也为1。 - SeeR
你能试着再显示/打印一下从GetString返回的字符串吗?我不知道这些方法的内部工作原理,但我同意它看起来非常奇怪。 - Kieren Johnstone
在我的电脑上显示为 (一个方块)。 - SeeR
显示剩余2条评论
2个回答

7

CP437对于范围在0-31的字符并非是双向的。正如您链接的维基百科页面所述:

对于许多用途,范围在0到31和代码127的代码将不会产生这些符号。它们中的一些(或全部)将被解释为ASCII控制字符。

将Unicode字符映射到受支持的CP437字符的范围内可以工作,但反过来就不行了。例如,以字节13和10表示的字符:如果您在CP437字符串中找到它们,很可能实际上希望保留回车和换行符,而不是转换为一个符号和一个音符。这种行为是正常的:这不是一个错误。


这可以称为窄化转换。 - Jodrell
1
天啊,讨厌被微软的设计决策打败。现在我需要找到/编写双向CP437编码。 :-( - SeeR
@SeeR:WinAPI 函数MultiByteToWideChar通过其 MB_USEGLYPHCHARS 标志支持此功能:“使用字形字符而不是控制字符。” 但要注意,如果您的文本中有 CRLF,它们将返回为“♪◙” - 因为您的文件不再具有任何 CR+LF,而是具有 八分音符+反白圆圈 - Ian Boyd

0

.NET支持两种不同的字符,它们都(通常)被呈现为§

char c1 = (char)21;
char c2 = (char)167;

Console.WriteLine(c1 == c2);  // prints false
Console.WriteLine(c1);        // prints §
Console.WriteLine(c2);        // prints §

字符21是一种特殊的控制字符,在文本模式下输出时呈现为§

CP437允许将21解释为控制字符或文字字面量§。显然,GetString选择将其解释为控制字符(这是完全有效的选项),因此将其映射到Unicode控制字符21而不是Unicode文字字面量§


1
在我的机器上,Console.WriteLine(c1) 打印出 EMPTY,而 Console.WriteLine(c2); 则打印出 § - Jalal Said
我认为是这样的,我正在使用Windows XP SP3和Visual Studio 2010。 - Jalal Said

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接