【问题标题】:Legacy Character Encoding传统字符编码
【发布时间】:2012-05-06 14:52:06
【问题描述】:

我正在处理 90 年代初编写的旧 Java 游戏的源代码。如果我没记错的话,它是为 JDK 1.1 编写的。

在代码中的某处,int 原语(在 0 到大约 120 的范围内)被转换为字符。这是一个例子:

char c = (char)(i+32);

这会导致大于 95 的整数出现问题。以下是测试用例的代码和一些输出:

for(int i = 120; i >= 0; i--)
   System.out.println(i + " -> " + (char)(i+32));

输出:

...
100 -> ?
99 -> ?
98 -> ?
97 -> ?
96 -> ?
95 -> 
94 -> ~
93 -> }
92 -> |
91 -> {
90 -> z
89 -> y
88 -> x
87 -> w
...
3 -> #
2 -> "
1 -> !
0 ->  

由于索引超出了正常字符值的范围,整数值似乎丢失了。

这似乎是游戏 UI 的客户端部分出现错误的根本原因。这个编码的整数被发送回客户端,然后客户端执行逆运算(从 char 中减去 32 并强制转换以获得 int 返回)。

似乎'?'由客户端处理模块按字面意思表示,因为该条被“?”的映射整数值冗余填充。直到服务器开始发回小于 95 的值。

  1. 作者的平台上可能使用了哪些字符编码?
  2. 我的平台上到底发生了什么不同的事情?
  3. 在您看来,解决此问题最简单的方法是什么?

【问题讨论】:

  • 如果它只使用 ASCII,它最多只能工作 95,因为 ASCII 只能达到 127 (95+32)。

标签: java character-encoding legacy legacy-code


【解决方案1】:

由于索引超出了正常字符值的范围,整数值似乎丢失了。

嗯,它并没有真正“丢失”——它只是进入了range of control characters

作者的平台上可能使用了哪些字符编码?

我不认为这是任何平台上的“正常”编码。

我的平台上到底发生了什么不同的事情?

不清楚您预期会发生什么,但这些字符无法在您的控制台中显示,因此将它们翻译成“?”

在您看来,解决这个问题最简单的方法是什么?

您必须首先根据您希望发生什么来更好地定义问题,以获得解决方案。目前尚不清楚这是否真的是一个主机游戏或其他什么,或者你想要发生的事情。

确切地想要首先确定行为,然后很容易实现它 - 我怀疑问题可能是你(还)没有非常清楚最终结果应该是什么。通常,只需非常明确地定义这一点就足以让您继续前进。

【讨论】:

  • 谢谢;我更新了我的帖子来描述我正在尝试解决的问题。
  • @kwikness:嗯,你现在还没有给出任何关于如何将字符传输回客户端的指示......如果这会丢失信息,那么详细信息该过程对于弄清楚正在发生的事情至关重要。
  • 大声笑——我指出了它们是如何在客户端处理的。我认为这就足够了。感谢您的帮助。
  • @kwikness:不,这不够:“这个编码的整数被发送回客户端,然后执行逆运算” - 没有说如何 编码后的整数被发送到客户端,我们无法判断它是否丢失了信息。如果您在客户端处理数据之前丢失数据,那么无论您做什么都将无法恢复数据。当我要求更多信息时,这是因为这些信息很重要。但是,嘿,如果您实际上并不需要帮助,那也没关系。
【解决方案2】:

char 在 Java 中是一个 16 位 Unicode 字符。旧代码可能期望将 int 值视为字节,然后您可以将字节转换为指定不同字符集的字符,直到您得到一个有意义的字符集(即new String(byteArrayData, "ASCII"))。

您需要考虑的是字节是用 Java 签名的,因此范围是 -128->+127。如果您的旧游戏代码期望使用扩展 ascii 集中的值 (> 127),那么您需要从任何 int > 127 中减去 256 以获得正确的字节值。有关详细信息,请参阅:How does Java convert int into byte?

【讨论】:

  • 您还应该考虑到 ASCII 本身只能达到 127 的事实。如果服务器使用 ASCII 编码将数据传输回客户端,那么任何超过 127 的字符都不会被正确传输。但 OP 似乎认为这不相关,出于某种原因......
【解决方案3】:

在您看来,解决这个问题最简单的方法是什么?

首先,您必须了解应用程序实际上试图输出什么;即这些整数值的真正含义。这将决定将它们呈现为(我猜)可打印字符的要求。

如果您只是想将整数呈现为可打印的东西,那么您可以使用实现为字符数组的查找表来实现;例如

char[] map = new char[128];  // ... or whatever the limit is 
for (int i = 0; i < 96; i++) {
    map[i] = (char) (i + 32);
}
// fill the rest of the array with suitable Unicode characters.
map[96] = ...
map[97] = ...

然后像这样映射字符:

char c = (i >= 0 && i < 128) ? map[i] : '?'; // ... or throw an exception.

【讨论】:

    【解决方案4】:

    可能是使用了 Win1252 等 8 位编码,可见字符在 80-9F 范围内。

    http://en.wikipedia.org/wiki/Windows-1252

    【讨论】:

      猜你喜欢
      • 2014-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-09
      • 2018-10-12
      • 2016-04-19
      • 1970-01-01
      • 2011-05-31
      相关资源
      最近更新 更多