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

piah890a  于 2023-01-01  发布在  Java
关注(0)|答案(3)|浏览(342)

我正在发送和接收来自服务器的字符串形式的产品信息,服务器接收和发送COBOLSs9(6)v99格式的产品价格。我无法在java中将给定的小数转换为该格式。
COBOL s9(6)V99格式示例:

  • 0000016H
  • 0000000元
    :目前我还没有实现转换,我正在寻找解决方案
nvbavucw

nvbavucw1#

建议

总体而言

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

Package

如果您可以获得Cobol Copybook,为什么不使用其中一个Cobol/Java包呢

  • JRecord
  • Cobol2J
      • 明星之星**
      • IBM**有相应的软件
    • 注意:**即使您没有完整的Cobol Copybook,您也可以为这一个字段设置一个Cobol Copybook,并且仍然使用一个包。Copybook将是:
01  MY-REC.
       03 FIELD-1              PIC S9(6)V99.

你需要知道的

没有一种单一的Cobol分区十进制格式,它随编译器和编码方式的不同而不同。要解码Zoned Decimal,您确实需要了解

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

在这种情况下我猜是的

  • 在IBM大型机或AS400上运行的IBM编译器
  • 美国EBCDIC(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钴

在本例中,它是EBCDIC。对于基于ASCII的代码,它又是不同的。这是JRecord用于Ascii带区十进制的通用转换类:

xjreopfe

xjreopfe2#

在我看来,这应该是相当简单的。这是假设,这似乎是从你的例子的情况下,这是一个分区十进制。
首先你需要得到数字的符号。简单地检查最后一个字符。如果它是一个非数字,那么它是负数(假设你使用F格式的正数)。一旦你得到了,然后你可以用正确的,等价的数字替换该字符。
现在您有了数字的字符串表示形式。
现在做

Integer result = Integer.valueOf(theInputString)

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

ibps3vxo

ibps3vxo3#

让服务器中的cobol将值移动到screen变量中会容易得多,如

77 S-VALUE PIC  ------9,99

并导出此变量,该变量易于读取,并且可以解析为Java双精度变量,其中:

Double value = Double.parseDouble(string);

Double value = new Double(string);

相关问题