EBCDIC 代码页不转换小写“a”

Posted

技术标签:

【中文标题】EBCDIC 代码页不转换小写“a”【英文标题】:EBCDIC code page does not convert lower case 'a' 【发布时间】:2013-05-20 23:27:14 【问题描述】:

我正在尝试使用 IBM 代码页将字符串从 ASCII 转换为 EBCDIC。转换是正确的,除了小写“a”被转换为不可打印的字符。

这是在 Windows 7 中运行的一段 groovy 脚本,用于说明问题。

groovy:000> letters='abcdABCD'
===> abcdABCD
groovy:000> String.format("%04x", new BigInteger(1, letters.getBytes())
===> 6162636441424344
groovy:000> lettersx=new String(letters.getBytes('IBM500'))
===> ?éâä┴┬├─
groovy:000> String.format("%04x", new BigInteger(1, lettersx.getBytes()))
===> 3f828384c1c2c3c4

转换为 EBCDIC 后,字符串中的所有字符都有效,但第一个字符除外,即小写“a”。尽我所能,我找不到关于这个问题的任何信息。我尝试了许多 IBM 代码页,结果相同(IBM01140、IBM1047 等)

【问题讨论】:

【参考方案1】:

问题出在这个表达式中:

new String(letters.getBytes('IBM500'))

letters.getBytes 创建一个字节数组,包含(十六进制):

 81 82 83 84 C1 C2 C3 C4

但随后您会立即使用您的平台默认编码将其转换回 Unicode 字符串:

 new String( <byte-array> );

如果您希望 String 中字符的序数值等于字节值,则必须指定执行此操作的编码,例如 ISO-8859-1:

new String(letters.getBytes('IBM500'), "ISO-8859-1")

您使用的编码没有为字节81 定义字符编码,因此它用? (3f) 替换它。您最有可能使用Windows-1252。

字符串包含字符,而不是字节。当从一个到另一个时,Java 将始终应用编码转换。

编辑:回复@mister270 的评论:

这里有一个Java程序来演示:

public class Ebcdic

    public static void main(String[] args) throws Exception
    
        String letters = "abcdABCD";

        byte[] ebcdic = letters.getBytes("IBM500");

        System.out.print("Ebcdic bytes:");
        for (byte b: ebcdic)
        
            System.out.format(" %02X", b & 0xFF);
        
        System.out.println();

        String lettersEbcdic = new String(ebcdic, "ISO-8859-1");

        System.out.print("Ebcdic bytes stored in chars:");
        for (char c: lettersEbcdic.toCharArray())
        
            System.out.format(" %04X", (int) c);
        
        System.out.println();

        System.out.println("Ebcdic bytes in chars printed in using my default platform encoding: " + lettersEbcdic);
    

输出是:

Ebcdic bytes: 81 82 83 84 C1 C2 C3 C4
Ebcdic bytes stored in chars: 0081 0082 0083 0084 00C1 00C2 00C3 00C4
Ebcdic bytes in chars printed in using my default platform encoding: ????��ǎ

这表明

使用“IBM500”正确地将 Ebcdic 转换为字节数组 使用“ISO-8859-1”将字节“身份”转换为字符的过程正确发生 我的系统没有将 Unicode 字符 U+0081 等转换为我的默认平台字符编码的映射,因此它显示为 ?

Java(Groovy 也是如此)在内部将字符存储为 Unicode。 UTF16,准确地说。如果您想将它们编码为 Ebcdic,那么它们将不再是字符并且不应再保存在字符串中。 Ebcdic 是一种 8 位编码,因此每个字符都可以存储在一个字节中。如果您需要与需要特定编码的系统(在您的情况下为 Ebcdic)进行交互,那么该系统确实应该接受字节,而不是字符串,否则您最终会遇到这种混乱。

如果您必须使用字符串来保存 Ebcdic 字节,那么无论何时使用 InputStream 或 OutputStream(包括 System.out)都必须使用 ISO-8859-1 编码,以确保您的 ebcdic 代码不会从字节“转换”到字符

【讨论】:

Adrian,我明白你的意思,但是使用 ISO-8859-1 会导致所有小写字母都返回为 x'3f'。 @mister270:如果这回答了你的问题,你可以点击答案顶部旁边的(见FAQ) 完成@adrianpronk 但我也发现了这个answer,它更详细地解释了整个事情。如果我第一次看到这个可能不会发布

以上是关于EBCDIC 代码页不转换小写“a”的主要内容,如果未能解决你的问题,请参考以下文章

Codeigniter 分页不呈现分页链接

vue10行代码实现上拉翻页加载更多数据,纯手写js实现下拉刷新上拉翻页不引用任何第三方插件

jsp错误页不跳转显示500

EBCDIC 到 ASCII 无法正常工作

ngx-分页单击下一页不起作用

在将 EBCDIC 转换为十六进制时需要帮助