java - 如何在Java中解析与cobol s9(6)v99格式的数据
Posted
技术标签:
【中文标题】java - 如何在Java中解析与cobol s9(6)v99格式的数据【英文标题】:How to parse data to and from cobol s9(6)v99 format in java 【发布时间】:2017-03-06 14:17:16 【问题描述】:我以字符串形式从服务器发送和接收产品信息,服务器以 COBOLS s9(6)v99 格式接收和发送产品价格。我无法转换在 java 中从或到这种格式的小数。
COBOL s9(6)V99 格式示例:
0000016H 0000000注意:目前我没有实现转换,我正在寻找解决方案
【问题讨论】:
那么您介意提供一些要解析的数据示例吗?我猜这里 99.9% 的用户从未使用过 COBOL! 见***.com/questions/3257771/… 我已经阅读了那个讨论,但它没有任何结果...... 所以,让发件人以您无需进行任何编码的格式发送它。选择对您来说方便的(在固定宽度的字段中),这是对 COBOL 程序的一个非常小的改动。 @theblitz 这不是负零。 【参考方案1】:建议
一般
更改 Cobol。如果将 cobol 更改为s9(6)V99 sign leading
,那么在 java 中处理起来会容易得多。在您的情况下,这可能不是一个选择
如果您可以获得 Cobol Copybook,请使用软件包
包
如果您可以获得 Cobol Copybook,为什么不使用其中一个 Cobol / Java 包
JRecord Cobol2J Legstar IBM 有这方面的软件注意:即使您没有完整的 Cobol Copybook,您也可以为此字段设置 Cobol Copybook,并且仍然使用包。抄写本是:
01 MY-REC.
03 FIELD-1 PIC S9(6)V99.
你需要知道的
没有一种单一的 Cobol Zoned Decimal 格式,它因编译器而异
编码是什么。要解码Zoned Decimal
,你真的需要知道
在这种情况下,我猜是
在 IBM 大型机或 AS400 上运行的 IBM 编译器 美国 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 码
在这种情况下,它是 EBCDIC。对于基于 ASCII 的 cobol,它又是不同的。这是JRecord Ascii Zoned-Decimal 的通用转换类:
https://sourceforge.net/p/jrecord/code/HEAD/tree/jrecord/Source/JRecord_Common/src/net/sf/JRecord/Types/TypeFjZoned.java注意:我是作者JRecord
【讨论】:
【参考方案2】:据我所知,它应该相当简单。这假设(从您的示例中似乎就是这种情况)这是一个分区十进制。
首先,您需要获取号码的符号。只需检查最后一个字符。如果它是非数字,那么它是负数(假设您使用 F 格式作为正数)。 一旦你有了它,你就可以用正确的等效数字替换那个字符。
您现在有了一个数字的字符串表示形式。
现在做
Integer result = Integer.valueOf(theInputString)
然后除以 100 并重新应用符号。 您也可以在调用 valueOf 之前将符号作为“-”或“+”添加到字符串中。
【讨论】:
“使用 F 格式表示正数”并不像您想象的那么普遍。 因为我同时打字,所以比你想象的要少得多。当然,对于大多数 COBOL 系统来说,这可能是一件非常非常糟糕的事情。也表示粗制滥造。 很久没用 Cobol 编程了。尽管如此,这个想法仍然存在。 @theblitz 你能描述一下这里的“H”和“”是什么意思吗 几个链接可以比我更好地解释它:faculty.cs.niu.edu/~byrnes/csci360/notes/360dec.htmv8doc.sas.com/sashtml/lrcon/z1265705.htm以上是关于java - 如何在Java中解析与cobol s9(6)v99格式的数据的主要内容,如果未能解决你的问题,请参考以下文章
你如何为 Cobol 字帖生成 java~jrecord 代码
在 AS400 上通过 Java 流式传输运行时进程执行(cobol obj)的结果时出现 MalformedInputException