C# 在.Net中解包Comp-3时遇到问题。Comp-3值中除了符号字符之外还有字母字符

C# 在.Net中解包Comp-3时遇到问题。Comp-3值中除了符号字符之外还有字母字符,c#,mainframe,bcd,ebcdic,comp-3,C#,Mainframe,Bcd,Ebcdic,Comp 3,我正在尝试使用.NET将大型机EDI文件导入回SQL 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

我正在尝试使用.NET将大型机EDI文件导入回SQL 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 Vagner创建的工具的帮助下加载了所有内容。我只是对“Unpack”函数做了一些修改,并将其修改为

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;
        }
    }
}
如您所见,我只能正确获得以下3个值:

00-09-10-20-00-0C -> 9102.0000
00-00-00-00-00-0C -> 0.0000
00-00-00-0C       -> 0.0000
如从该源引用的:。我对Comp-3有以下理解:

COBOL Comp-3是一种二进制字段类型,它使用一种称为二进制编码十进制(BCD)的表示法,将两位数字(“打包”)到每个字节中

二进制编码的十进制(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

除符号字符外,这些值还有其他字符。我有一种感觉,数据已经被转换了,因为如果不是,那么应该没有可读的值,除非你应用了编码。我仍然不确定这一点,并希望对此有任何见解。谢谢。

首先,
PICX
在COBOL中不是Unicode

引用我自己的话

大型机数据通常包括文本和二进制数据 在单个记录中,例如名称、货币金额和 数量:

ar%。

…这将是

x'C8969797859940404040400C799818385404040404040400081996C004B'

…用十六进制。这是代码页37,通常称为EBCDIC

[…]转换为代码页1250,通常在Microsoft上使用 Windows,您将以

x'486F70706722020200477261636552020202020061722002E'

…文本数据被翻译,但压缩数据被销毁。 压缩数据在最后一个半字节中不再有有效符号 最后一个字节的下半部分),货币金额本身已 由于以下原因,数量发生了变化(从小数点75变为小数点11776 代码页转换和将大端数字作为 小端数)

您的数据可能是在从大型机传输时转换的代码页。如果您知道原始代码页及其转换为的代码页,那么您可能能够解读打包的数据


我说可能是因为,如果你幸运的话,你的十六进制值将在原始代码页中与十六进制值一一对应。请注意,EBCDIC x'15'和x'0D'映射到ASCII x'0D'是很常见的。

您尝试转换的字段看起来已损坏。他们有没有通过Ebcdic到Ascii的转换??,他们看起来可能是。嗨,布鲁斯,谢谢你的回复。我还假设数据已损坏,但不确定是否确实如此,因为我也得到了一些正确的值。该数据由我们的客户提供,并且有一家第三方公司负责这些文件的导出。有没有解释为什么有些数据是正确的,有些是不正确的?这可能是一个出口问题?谢谢。另外,我真的不能立即假设数据已损坏,因为有正确的值,并且所有值的末尾都有一个符号字符。如果有一个从Ebcdic到Ascii的转换,我会假定有些值的末尾不会有符号字符。我真的不确定这一点,但我的假设正确吗?谢谢。在进行任何ebcdic ascii转换之前,必须将任何压缩的十进制字段转换为显示格式,即纯文本。这种转换只看到位或字节,而不是文本或数字,因此无论人类如何看待数据,都会相应地转换数据。感谢NicC的回复。但问题是,第三方提供商不会修改提供的格式。感谢您的见解cschneid。我还假设发送给我们的当前数据已经转换为代码页1250,因为除了压缩字段之外,大多数字段已经可读。通常,如果它是二进制EBCDIC格式,如果不应用编码,则无法读取。我可能并不幸运,因为当前文件中的十六进制值似乎没有一一对应。我可能需要与客户就此进行协调,并请求一个原始二进制文件。非常感谢你在这方面的帮助!
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