Java-отображение для отображения cobol и распакованных числовых полей

Я запутался 9(формат отображения) и S9 (без упаковки числовой) тип. Я читал вывод тетради из хранимой процедуры DB2, используя Java

* copy book
05 ABC PIC X(01).
05 XYZ PIC +9(09).

Используя приведенный ниже Java-код, я смог правильно прочитать значения. Знак числа также очень прост в обращении, так как - или же +

// java code 
cobolResults.subString(1,1);
cobolResults.subString(2,9);

Теперь тетрадь изменена, чтобы дать распакованный номер, как показано ниже:

05 ABC PIC X(01).
05 XYZ PIC S9(09).

Я не уверен, что будет правильной логикой в ​​Java для чтения числа с правильным знаком?

1 ответ

Решение

Для начала есть пакеты от IBM & Legstar для генерации классов Java из Cobol Copybooks. Мой собственный пакет JRecord также может быть использован, но он ориентирован на файлы, а не на онлайн-обработку.

В основном последний символ поля содержит знак + число. Я предполагаю, что данные поступают с мэйнфрейма; Поэтому для США - Ebcdic (CP037 / IBM237) последняя цифра будет

          0 1 2 3 4 5 6 7 8 9
positive  { A B C D E F G H I
negative  } J K L M N O P Q R 

Таким образом, для +123 это будет 00000012C (C = +3), а -123 будет 00000012L.

Что еще хуже, +0 и -0 различны в разных диалектах EBCIDIC и ASCII. Поэтому вам нужно либо точно знать, какая версия Ebcidic используется, либо вам необходимо выполнить преобразование на уровне байтов.

Метод fromZoned в JRecord Conversion выполняет преобразование:

    private static int positiveDiff = 'A' - '1';
    private static int negativeDiff = 'J' - '1';

    private static char positive0EbcdicZoned = '{';
    private static char negative0EbcdicZoned = '}';

    public static String fromZoned(String numZoned) {
        String ret;
        String sign = "";
        char lastChar, ucLastChar;

        if (numZoned == null || ((ret = numZoned.trim()).length() == 0) || ret.equals("-")) {
            return "";
        }

        lastChar = ret.charAt(ret.length() - 1);
        ucLastChar = Character.toUpperCase(lastChar);


        switch (ucLastChar) {
        case 'A': case 'B': case 'C': 
            case 'D': case 'E': case 'F':
            case 'G': case 'H': case 'I':
            lastChar = (char) (ucLastChar - positiveDiff);
            break;
        case 'J': case 'K': case 'L':
        case 'M': case 'N': case 'O':
        case 'P': case 'Q': case 'R':
            sign = "-";
            lastChar = (char) (ucLastChar - negativeDiff);
            break;
        default:
            if (lastChar == positive0EbcdicZoned) {
                lastChar = '0';
            } else if (lastChar == negative0EbcdicZoned) {
                lastChar = '0';
                sign = "-";
            }           
        }
        ret = sign + ret.substring(0, ret.length() - 1) + lastChar;

         return ret;
    }

Но это проще сделать на уровне байтов, это должно быть примерно так (хотя код не тестируется):

    private static final byte HIGH_NYBLE = (byte) 0xf0;
    private static final byte LOW_NYBLE  = (byte) 0x0f;
    private static final byte ZONED_POSITIVE_NYBLE_OR = (byte) 0xCF;
    private static final byte ZONED_NEGATIVE_NYBLE_OR = (byte) 0xDF;
    private static final byte ZONED_NEGATIVE_NYBLE_VALUE = (byte) 0xD0;                        

    signByte = bytes[bytes.length - 1];

    negative = false;
    if (((byte) (signByte & HIGH_NYBLE)) == ZONED_NEGATIVE_NYBLE_VALUE) {
        negative = true;
    }

    long result = 0;
    for (int i = 0; i < bytes.length; i++) {
        result = result * 10 + (bytes[i] & LOW_NYBLE);
    }

    if (negative) {
       result = -1 * result;
    }
Другие вопросы по тегам