从我们的供应商提供给我们的文件中解包包含数字和日期数据的COMP-3字段时,我们遇到了一些困难。
文件规范提供以下信息:
0066-0070 DATE-OPENED S9(9) COMP-3
规范表明日期将扩展为MMDDYYYY格式。
当我从文件中检索这个数据块时,我可以将它加载到内存中,看看我检索了5个字节的数据。 (在文件中,每个字符有一个字节。)检索的字节如下:
0: 10
1: 0
2: 18
3: 0
4: 2
没有任何迹象超过最重要的数字(它总是出现的地方),因此这里不是问题。这些位扩展为以下半字节:
0 1 0 0 1 2 0 0 0 2
这里有几个问题:
01001200极不可能代表MMDDYYYY格式的有效日期,但这似乎是数据打包到字段中的方式。
解压缩COMP-3字段时,模板指定它应扩展为9个字符,但如果展开COMP-3,则其大小将始终 double(生成一个具有偶数个字符的字符串)。因此,预期大小与未打包大小之间存在不匹配。
我在网上找不到的算法似乎无法解压缩这些数据。似乎没有什么能够在源文件中为任何(假设的)BCD值提供可识别的日期。
此时我怀疑我们可能没有处理真正的BCD格式。但是,请记住,我应该总是怀疑自己而不是工具,我正在寻找建议,因为我对COMP-3格式的理解以及我所看到的数据的性质都可能出错。
我对格式的理解来自以下来源:
值得注意的是,在尝试打开包装之前,我曾尝试将数据从EBCDIC转换为ASCII,反之亦然;既没有产生任何可理解的结果。我尝试过在互联网上找到的每一种算法,但它们似乎都没有产生任何有用的结果。
我想,最后,我的问题是:我实际上是在处理BCD或COMP-3数据吗?
更新
回答一些问题:
我们手头有原始和未解析的文件作为参考资料。我期待回来的日期与06152008的情况类似(这是我头脑中的一个,但你得到了主旨)。 I' m计算的值是 nothing 。
根据请求,个别小吃:
0 1 0 0 1 2 0 0 0 2
对于那些对我如何做这件事感兴趣的人来说,正在拆包的课程:
using System.Collections.Generic;
using System.Linq;
using System.Text;
internal class PackedDecimal
{
#region Fields
private bool _isPositive;
private bool _isNegative;
private bool _isUnsigned = true;
#endregion
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="PackedDecimal"/> class.
/// </summary>
public PackedDecimal()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PackedDecimal"/> class.
/// </summary>
/// <param name="compressedDecimal">The compressed decimal.</param>
public PackedDecimal(string compressedDecimal)
{
this.ParsedValue = this.Parse(compressedDecimal);
}
#endregion
#region Properties
/// <summary>
/// Gets the bytes.
/// </summary>
public IEnumerable<byte> Bytes { get; private set; }
/// <summary>
/// Gets the hexadecimal values.
/// </summary>
public IEnumerable<string> HexValues { get; private set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is positive.
/// </summary>
/// <value>
/// <c>true</c> if this instance is positive; otherwise, <c>false</c>.
/// </value>
public bool IsPositive
{
get { return this._isPositive; }
set
{
this._isNegative = !this.IsPositive;
this._isUnsigned = false;
}
}
/// <summary>
/// Gets or sets a value indicating whether this instance is negative.
/// </summary>
/// <value>
/// <c>true</c> if this instance is negative; otherwise, <c>false</c>.
/// </value>
public bool IsNegative
{
get { return this._isNegative; }
set
{
this._isNegative = value;
this._isPositive = !value;
this._isUnsigned = false;
}
}
/// <summary>
/// Gets a value indicating whether this instance is unsigned.
/// </summary>
/// <value>
/// <c>true</c> if this instance is unsigned; otherwise, <c>false</c>.
/// </value>
public bool IsUnsigned { get { return this._isUnsigned; } }
/// <summary>
/// Gets the nibbles.
/// </summary>
public IEnumerable<int> Nibbles { get; private set; }
/// <summary>
/// Gets the parsed value.
/// </summary>
public string ParsedValue { get; private set; }
#endregion
/// <summary>
/// Parses the specified value.
/// </summary>
/// <param name="value">The value.</param>
/// <returns></returns>
public string Parse(string value, SourceEncoding sourceEncoding = SourceEncoding.Ascii, int decimalPlaces = 0)
{
var localValue = value; // Encoding.Convert(Encoding.ASCII, Encoding.GetEncoding("IBM037"), value.ToByteArray()).FromByteArray();
var sign = this.GetSign(localValue, out localValue);
var bytes = localValue.ToByteArray();
var nibbles = new List<int>();
var buffer = new StringBuilder();
foreach (var b in bytes)
{
var hi = (int)b.HiNibble();
var lo = (int)b.LoNibble();
nibbles.Add(hi);
nibbles.Add(lo);
buffer.AppendFormat("{0}{1}", hi, lo);
}
this.Bytes = bytes;
this.Nibbles = nibbles;
this.HexValues = nibbles.Select(v => v.ToString("X"));
switch (sign)
{
case Sign.Unsigned:
this.ParsedValue = buffer.ToString();
break;
case Sign.Positive:
this.ParsedValue = "+" + buffer;
break;
case Sign.Negative:
this.ParsedValue = "-" + buffer;
break;
}
this.IsPositive = sign == Sign.Positive;
this.IsNegative = sign == Sign.Negative;
return this.ParsedValue;
}
#region GetSign Method
/// <summary>
/// Gets the sign for the packed decimal represented by this instance.
/// </summary>
/// <param name="value">The value to analyze.</param>
/// <param name="buffer">Receives <paramref name="value"/>, less the sign digit if it is present.</param>
/// <returns>The sign for the packed decimal represented by this instance.</returns>
/// <remarks>If the value provided does not include a sign digit, it is assumed to be unsigned.</remarks>
private Sign GetSign(string value, out string buffer)
{
var lastDigit = value.ToByteArray().Last();
var loNibble = lastDigit.LoNibble();
var hiNibble = lastDigit.HiNibble();
var result = Sign.Unsigned;
var hasSignDigit = true;
switch (hiNibble)
{
case 0xC0: // "c"
result = Sign.Positive;
break;
case 0xD0: // "d"
result = Sign.Negative;
break;
case 0xF0: // "f"
result = Sign.Unsigned;
break;
default:
hasSignDigit = false;
break;
}
// Remove the sign digit if it's present.
buffer = hasSignDigit
? value.Substring(0, value.Length - 1) + loNibble
: value;
return result;
}
#endregion
#region Sign Enum
private enum Sign
{
Unsigned,
Positive,
Negative
}
#endregion
}
支持它的扩展方法:
using System;
using System.Linq;
using System.Text;
public static class Extensions
{
/// <summary>
/// Gets the high nibble (the high 4 bits) from a byte.
/// </summary>
/// <param name="value">The byte from which the high 4-bit nibble will be retrieved.</param>
/// <returns>A byte containing the value of this byte, with all bits shifted four bits to the right.</returns>
public static byte HiNibble(this byte value)
{
return (byte)((value & 0xF0) >> 4);
}
/// <summary>
/// Gets the low nibble (the lowest 4 bits) from this byte.
/// </summary>
/// <param name="value">The byte from which the low 4-bit nibble will be retrieved.</param>
/// <returns>A byte containing the value of this byte, with the high four bits discarded.</returns>
public static byte LoNibble(this byte value)
{
return (byte)(value & 0x0F);
}
/// <summary>
/// Gets the individual bytes from a string.
/// </summary>
/// <param name="value">The string to convert to a byte array.</param>
/// <returns>An array of bytes representing the string.</returns>
public static byte[] ToByteArray(this string value)
{
var bytes = new byte[Encoding.ASCII.GetByteCount(value)];
Buffer.BlockCopy(value.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
}
public enum SourceEncoding
{
Ascii,
Ebcdic
}