我正试图使用.NET将大型机EDI文件导入Server,并且在解压一些comp-3字段时遇到了问题。
此文件来自我们的一个客户端,我有以下字段的复制书布局:
05 EH-GROSS-INVOICE-AMT PIC S9(07)V9999 COMP-3.
05 EH-CASH-DISCOUNT-AMT PIC S9(07)V9999 COMP-3.
05 EH-CASH-DISCOUNT-PCT PIC S9(03)V9999 COMP-3.我将只关注这3个字段,因为所有其他字段都是PIC(X),并且已经是Unicode值。在这个由Max创建的工具Ebcdic2Ascii的帮助下,我加载了所有的东西。我只是对“解包”函数做了一些修改,并将其修改为
private string Unpack(byte[] packedBytes, int decimalPlaces, out bool isParsedSuccessfully)
{
isParsedSuccessfully = true;
return BitConverter.ToString(packedBytes);
}为了获得以下示例数据:
EH-GROSS-INVOICE-AMT EH-CASH-DISCOUNT-AMT EH-CASH-DISCOUNT-PCT
----------------------------------------------------------------------
00-1A-1A-03-26-0C 00-00-00-00-00-0C 00-00-00-0C
00-0A-1A-1A-00-0C 00-00-1A-1A-2D-0C 00-1A-00-0C
00-09-10-20-00-0C 00-00-10-1A-1A-0C 00-1A-00-0C下面是我根据对Comp-3值的理解为解压缩这些值而创建的示例代码:
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var result1 = UnpackMod("00-1A-1A-03-26-0C", 4);
var result2 = UnpackMod("00-00-00-00-00-0C", 4);
var result3 = UnpackMod("00-00-00-0C", 4);
Console.WriteLine($"{result1}\n{result2}\n{result3}\n");
var result4 = UnpackMod("00-0A-1A-1A-00-0C", 4);
var result5 = UnpackMod("00-00-1A-1A-2D-0C", 4);
var result6 = UnpackMod("00-1A-00-0C", 4);
Console.WriteLine($"{result4}\n{result5}\n{result6}\n");
var result7 = UnpackMod("00-09-10-20-00-0C", 4);
var result8 = UnpackMod("00-00-10-1A-1A-0C", 4);
var result9 = UnpackMod("00-1A-00-0C", 4);
Console.WriteLine($"{result7}\n{result8}\n{result9}");
Console.ReadLine();
}
/// <summary>
/// Method for unpacking Comp-3 fields.
/// </summary>
/// <param name="hexString"></param>
/// <param name="decimalPlaces"></param>
/// <returns>Returns numeric string if parse was successful; else Return input hex string</returns>
private static string UnpackMod(string inputString, int decimalPlaces)
{
var outputString = inputString;
// Remove "-".
outputString = outputString.Replace("-", "");
// Check last character for sign.
string lastChar = outputString.Substring(outputString.Length - 1, 1);
bool isNegative = (lastChar == "D" || lastChar == "B");
// Remove sign character.
if (lastChar == "C" || lastChar == "A" || lastChar == "E" || lastChar == "F" || lastChar == "D" || lastChar == "B")
{
outputString = outputString.Substring(0, outputString.Length - 1);
}
// Place decimal point.
outputString = outputString.Insert(outputString.Length - decimalPlaces, ".");
// Check if parsed value is numeric. This will also eliminate all leading 0.
var isParsedSuccessfully = decimal.TryParse(outputString, out decimal decimalValue);
// If isParsedSuccessfully is true then return numeric string else return inputString..
string result = "NULL";
if (isParsedSuccessfully)
{
// Convert value to negative.
if (isNegative)
{
decimalValue = decimalValue * -1;
}
result = decimalValue.ToString();
}
return result;
}
}
}在运行示例代码之后,我能够获得以下结果:
EH-GROSS-INVOICE-AMT EH-CASH-DISCOUNT-AMT EH-CASH-DISCOUNT-PCT
----------------------------------------------------------------------
NULL 0.0000 0.0000
NULL NULL NULL
9102.0000 NULL NULL 如您所见,我只能正确地获得以下3个值:
00-09-10-20-00-0C -> 9102.0000
00-00-00-00-00-0C -> 0.0000
00-00-00-0C -> 0.0000来自这个源的引用:http://www.3480-3590-data-conversion.com/article-packed-fields.html。我对Comp-3有以下的理解:
COBOL Comp-3是一种二进制字段类型,它使用名为二进制编码十进制( BCD )的符号将("packs")两位数放入每个字节中。二进制编码的十进制(BCD)数据类型正如它的名称所暗示的--它是一个以十进制(基数10)表示的值,每个数字都是二进制编码的。因为一个数字只有十个可能的值(0-9)。最小有效字节的低比特用于存储数字的符号。它只存储符号,而不存储数字。"C“十六进制为正,"D”十六进制为负,"F“十六进制为无符号。
因为我知道BCD只应该是0-9的值,而且在结尾只应该有一个字符,可以是"C“、"D”或"F“。我不知道如何解压下列值:
00-1A-1A-03-26-0C
00-0A-1A-1A-00-0C
00-00-1A-1A-2D-0C
00-1A-00-0C
00-00-10-1A-1A-0C
00-1A-00-0C这些值在符号字符之外还有其他字符。我有一种感觉,数据已经被转换了,因为如果不是的话,就不应该有可读的值,除非您应用了编码。我仍然不确定这一点,并会喜欢任何有关这方面的见解。谢谢。
发布于 2021-01-04 15:18:30
首先,PIC X不是COBOL中的Unicode。
引用这里的话..。
大型机数据通常会将文本和二进制数据同时包含在单个记录中,例如名称、货币数量和数量:
Hopper Grace ar% ....which会是..。x'C8969797859940404040C799818385404040404081996C004B'...in十六进制这是代码页37,通常称为EBCDIC。 ...Converting到第1250页的代码,通常在Microsoft上使用,您将以.x'486F707065722020202047726163652020202020617225002E'...where文本数据被翻译,但是打包的数据被销毁。打包的数据在最后一个小字节(最后一个字节的下半部分)中不再有一个有效的符号,货币数量本身也已经改变了(由于代码页转换和一个大的endian数字作为一个小的endian数字的损坏,从小数点75到小数点11,776 )。
您的数据很可能是在从大型机传输时转换的代码页。如果您知道原始代码页及其转换到的代码页,那么您可能能够解读打包的数据。
我说可能是因为,如果你幸运的话,你所拥有的十六进制值将被映射到原始代码页面中的十六进制值一对一的映射。请注意,EBCDIC x'15‘和x'0D’映射到ASCII x'0D‘是很常见的。
https://stackoverflow.com/questions/65559596
复制相似问题