如何在java中解析cobol s9(6)v99格式的数据

时间:2017-03-06 14:17:17

标签: java parsing cobol

我从服务器发送和接收产品信息作为字符串,服务器以COBOLS s9(6)v99 格式接收并发送产品价格。我无法转换在java中给出十进制或者给出这种格式。

COBOL s9(6)V99格式exmaples:

  • 0000016H
  • 0000000 {

注意:目前我没有实施转化,我正在寻找解决方案

2 个答案:

答案 0 :(得分:6)

建议

一般

  • 更改Cobol。如果cobol改为s9(6)V99 sign leading,那么在java中处理它会容易得多。在您的情况下,这可能不是一个选项
  • 如果您可以使用 Cobol Copybook 使用套餐

软件包

如果你能获得 Cobol Copybook ,为什么不使用其中一个Cobol / Java软件包

注意:即使您没有Full Cobol Copybook,也可以为此一个字段设置Cobol Copybook并仍使用包。本抄写本将是:

   01  MY-REC.
       03 FIELD-1              PIC S9(6)V99.

您需要了解的内容

没有一个单独的Cobol Zoned Decimal格式,它从compilere到Compiler和 编码是什么。要解码Zoned Decimal,您真的需要知道

  • Cobol编译器
  • 服务器上使用的编码

在这种情况下,我猜它是

  • 在IBM Mainframe或AS400上运行的IBM Compiler
  • 美国Ebdic(IBM037)或类似的东西(绝对不是德国EBCDIC(IBM273))

解释分区小数

在分区十进制中:

  • S 表示它是签名号码;该标志在最后一位数字上为overpunched
  • 9 代表单个数字
  • V 代表assumed小数位

所以s9(6)V99是带符号的数字,小数位前有6位数,

后有2位数

编码的影响

服务器使用的encoding(字符集)决定了符号数字的表示方式。 对于美国(和英国),Ebcdic + 0 / -0是{ / },但它们与德国Ebcdic不同。 对于ASCII服务器,它又是不同的

Java代码

ebcdic转换代码(注意它仍然需要针对假定的十进制进行调整):

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;
}

设置+0/-0个字符

public static void setDefaultEbcidicCharacterset(String charset) {
    if (getHold(charset).isEbcdic) {
        byte[] b = {(byte) 0xC0, (byte) 0xD0};
        String s = new String(b, charset);
        if (s.length() == 2) {
            positive0EbcdicZoned = s.charAt(0);
            negative0EbcdicZoned = s.charAt(1);
        }
    }
}

导出符号(用于EBCDIC编码)的另一种方法是将符号转换回原始字节:

private static final byte HIGH_NYBLE = (byte) 0xf0;
private static final byte ZONED_NEGATIVE_NYBLE_VALUE = (byte) 0xD0;

    String Sign = "";
    byte signByte = signStr.getBytes(encoding)[0];
    if (((byte) (signByte & HIGH_NYBLE)) == ZONED_NEGATIVE_NYBLE_VALUE) {
        sign = "-";
    }
    byte lastDigitBytes = (byte) (signByte | HIGH_NYBLE);

ASCII Cobols

在这种情况下,它是EBCDIC。对于基于ASCII的cobols,它又是不同的。这是Ascii Zoned-Decimal的JRecord泛型转换类:

注意:我是作者JRecord

答案 1 :(得分:0)

从我所看到的,它应该是相当简单的。从您的示例中可以看出,这是一个Zoned Decimal。

首先,您需要获得该号码的标志。只需检查最后一个字符。如果它是非数字,则它是负数(假设您使用F格式表示正数)。 完成后,您可以使用正确的等效数字替换该字符。

您现在有一个数字的字符串表示。

现在做

Integer result = Integer.valueOf(theInputString)

然后除以100并重新应用符号。 您也可以将标志添加为" - "或" +"调用valueOf之前的字符串。