使用的 JDK 中不存在字符集

问题描述 投票:0回答:1

我有一个java系统进行通信,作为不同系统(java、大型机等)的网关。该java系统使用例如utf8接收请求并将其转换为目标的编码

问题在于,有一个大型机系统正在使用这种晦涩的编码,而我们正在使用的 JDK 不提供这种编码(该字符集是 IBM-924,它是 IBM-1047 的“衍生品”https://en .wikibooks.org/wiki/Character_Encodings/Code_Tables/EBCDIC/EBCDIC_1047)。 系统。

据我所知,该字符集似乎仅随 IBM JDK 提供,这不是我们使用或想要使用的字符集。

是否有一种方法可以将 IBM JDK 上存在的这一特定字符集合并到例如 openjdk 中? 如果没有,除了手动创建字符集之外还有其他选择吗? 如果是这样,有没有办法重用 IBM-1047 编码并替换 11 个不匹配的字符?

我尝试使用 IBM JDK 上存在的 charsets.jar 来合并字符集,但它遇到了问题,因为该 jar 依赖于仅存在于 IBM JDK 的 rt.jar 上的类,我当然不希望替换 rt.jar,因为它可能会导致不必要的副作用。

java character-encoding mainframe charset
1个回答
0
投票

哦,IBM_924 在整个互联网上几乎不存在。环顾四周,它似乎要么是 ISO-8859-15(这是 JDK 附带的东西,所以只需使用 Charset.forName("ISO-8859-15"),或者..

这个

这是我从某个随机项目中找到的一些随机映射文件(诚然,来自 unicode 组织的 icu-data 项目;就来源而言,应该具有足够的权威性)。您阅读如下:

一行可能包含:

<UFF5E> \xA1 |1

这意味着:

如果您在数据流中看到字节
    0xA1
  • ...
    那么它代表unicode表中的字符0xFF5E。
  • |1
  • 或多或少意味着:这可能不完全准确。我认为这与您的需求无关。
    
    
  • 幸运的是,作为 ISO-8559 变体,它只是“1 个字节 = 1 个字符”,因此,最多只需要 256 个不同的字节值来映射到一个字符。

这意味着编写自己的字符集实现很简单!

因此您已经解决了所有问题:将字符集放在您自己的项目中,现在您没有依赖项,也无需依赖内置 IBM-924 的 JVM。

不太难。

创建一个名为

Ibm924CharsetProvider.java

的源文件并将其复制/粘贴到其中:

// Written by Reinier Zwitserloot
// Public domain - use however you like.

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.charset.spi.CharsetProvider;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class Ibm924CharsetProvider extends CharsetProvider {
    private static final Charset IBM924 = new Ibm924Charset();
    private static final List<Charset> IBM924_LIST = Collections.singletonList(IBM924);
    
    public static final Charset ibm924() {
        return IBM924;
    }
    
    @Override public Iterator<Charset> charsets() {
        return IBM924_LIST.iterator();
    }
    
    @Override public Charset charsetForName(String charsetName) {
        if (charsetName.equals(IBM924.name())) return IBM924;
        if (IBM924.aliases().contains(charsetName)) return IBM924;
        
        return null;
    }
    
    public static void main(String[] args) throws Exception {
        String in = "Hello, World!";
        byte[] b = in.getBytes(ibm924());
        System.out.print(in + " ->");
        for (byte a : b) System.out.printf(" %02X", a);
        System.out.println();
        String in2 = new String(b, ibm924());
        System.out.println("... -> " + in2);
        System.out.println("Equal? " + in.equals(in2));
    }
}

class Ibm924Charset extends Charset {
    public Ibm924Charset() {
        super("IBM-924", new String[] { "IBM924", "Cp924", "Cp-924" });
    }
    
    @Override public boolean contains(Charset cs) {
        return cs.name().equals("US-ASCII");
    }
    
    @Override public CharsetDecoder newDecoder() {
        return new CharsetDecoder(this, 1F, 1F) {
            @Override protected CoderResult decodeLoop(ByteBuffer from, CharBuffer to) {
                while (from.hasRemaining()) {
                    if (!to.hasRemaining()) return CoderResult.OVERFLOW;
                    byte c = from.get();
                    char d = IBM924[c & 0xFF];
                    to.put(d);
                }
                
                return CoderResult.UNDERFLOW;
            }
        };
    }
    
    @Override public CharsetEncoder newEncoder() {
        return new CharsetEncoder(this, 1F, 1F) {
            @Override protected CoderResult encodeLoop(CharBuffer from, ByteBuffer to) {
                while (from.hasRemaining()) {
                    if (!to.hasRemaining()) return CoderResult.OVERFLOW;
                    char d = from.get();
                    Byte v = LOOKUP.get(d);
                    if (v == null) {
                        // 'un'consume the character we consumed
                        from.position(from.position() - 1);
                        return CoderResult.unmappableForLength(1);
                    }
                    to.put(v.byteValue());
                }
                
                return CoderResult.UNDERFLOW;
            }
        };
    }
    
    private static final char[] IBM924 = {
        '\u0000', '\u0001', '\u0002', '\u0003', '\u009C', '\u0009', '\u0086', '\u007F',
        '\u0097', '\u008D', '\u008E', '\u000B', '\u000C', '\r', '\u000E', '\u000F',
        '\u0010','\u0011','\u0012','\u0013', '\u009D','\u0085','\u0008','\u0087',
        '\u0018','\u0019','\u0092','\u008F', '\u001C','\u001D','\u001E','\u001F',
        '\u0080','\u0081','\u0082','\u0083', '\u0084','\n','\u0017','\u001B',
        '\u0088','\u0089','\u008A','\u008B', '\u008C','\u0005', '\u0006', '\u0007',
        '\u0090', '\u0091', '\u0016', '\u0093', '\u0094', '\u0095', '\u0096', '\u0004',
        '\u0098', '\u0099', '\u009A', '\u009B', '\u0014', '\u0015', '\u009E', '\u001A',
        '\u0020', '\u00A0', '\u00E2', '\u00E4', '\u00E0', '\u00E1', '\u00E3', '\u00E5',
        '\u00E7', '\u00F1', '\u00DD', '\u002E', '\u003C', '\u0028', '\u002B', '\u007C',
        '\u0026', '\u00E9', '\u00EA', '\u00EB', '\u00E8', '\u00ED', '\u00EE', '\u00EF',
        '\u00EC', '\u00DF', '\u0021', '\u0024', '\u002A', '\u0029', '\u003B', '\u005E',
        '\u002D', '\u002F', '\u00C2', '\u00C4', '\u00C0', '\u00C1', '\u00C3', '\u00C5',
        '\u00C7', '\u00D1', '\u0160', '\u002C', '\u0025', '\u005F', '\u003E', '\u003F',
        '\u00F8', '\u00C9', '\u00CA', '\u00CB', '\u00C8', '\u00CD', '\u00CE', '\u00CF',
        '\u00CC', '\u0060', '\u003A', '\u0023', '\u0040', '\'', '\u003D', '\u0022',
        '\u00D8', '\u0061', '\u0062', '\u0063', '\u0064', '\u0065', '\u0066', '\u0067',
        '\u0068', '\u0069', '\u00AB', '\u00BB', '\u00F0', '\u00FD', '\u00FE', '\u00B1',
        '\u00B0', '\u006A', '\u006B', '\u006C', '\u006D', '\u006E', '\u006F', '\u0070',
        '\u0071', '\u0072', '\u00AA', '\u00BA', '\u00E6', '\u017E', '\u00C6', '\u20AC',
        '\u00B5', '\u007E', '\u0073', '\u0074', '\u0075', '\u0076', '\u0077', '\u0078',
        '\u0079', '\u007A', '\u00A1', '\u00BF', '\u00D0', '\u005B', '\u00DE', '\u00AE',
        '\u00A2', '\u00A3', '\u00A5', '\u00B7', '\u00A9', '\u00A7', '\u00B6', '\u0152',
        '\u0153', '\u0178', '\u00AC', '\u0161', '\u00AF', '\u005D', '\u017D', '\u00D7',
        '\u007B', '\u0041', '\u0042', '\u0043', '\u0044', '\u0045', '\u0046', '\u0047',
        '\u0048', '\u0049', '\u00AD', '\u00F4', '\u00F6', '\u00F2', '\u00F3', '\u00F5',
        '\u007D', '\u004A', '\u004B', '\u004C', '\u004D', '\u004E', '\u004F', '\u0050',
        '\u0051', '\u0052', '\u00B9', '\u00FB', '\u00FC', '\u00F9', '\u00FA', '\u00FF',
        '\\', '\u00F7', '\u0053', '\u0054', '\u0055', '\u0056', '\u0057', '\u0058',
        '\u0059', '\u005A', '\u00B2', '\u00D4', '\u00D6', '\u00D2', '\u00D3', '\u00D5',
        '\u0030', '\u0031', '\u0032', '\u0033', '\u0034', '\u0035', '\u0036', '\u0037',
        '\u0038', '\u0039', '\u00B3', '\u00DB', '\u00DC', '\u00D9', '\u00DA', '\u009F',
    };
    
    private static final Map<Character, Byte> LOOKUP;
    static {
        Map<Character, Byte> map = new HashMap<>();
        for (int i = 0; i < IBM924.length; i++) map.put(IBM924[i], (byte) i);
        LOOKUP = Collections.unmodifiableMap(map);
    }
}

作为提供者使用

如果您想要例如

new String(bytes, "IBM-924")

要工作,以及将其列在所有可用字符集列表中,需要注册此类。为此,您可以将完全限定的类名(例如,该字符串)粘贴到一个空的文本文件中。您将此文本文件命名为

com.foo.yourapp.util.Ibm924CharsetProvider
。该文件需要位于您的 jar 中,路径为
java.nio.charset.spi.CharsetProvider
。然后,如果该 jar 位于您的类路径中,那么一切就应该可以正常工作。
哦,听起来很复杂
您实际上并不需要这样做 - 这只是为了确保 

META-INF/services/java.nio.charset.spi.CharsetProvider

作为字符串能够正常工作。您可以按原样使用它,而无需注册提供商。请参阅代码片段中的

"IBM-924"

方法,其中我不费心注册它,而是直接使用

main
对象。
运行它,它会打印:
Charset

© www.soinside.com 2019 - 2024. All rights reserved.