如何在C#中将基数10(十进制)字符串转换为字节数组_directly_?

时间:2016-02-05 08:17:51

标签: c# string bytearray base radix

我希望获取一个可变长度的字符串输入,以数字方式解释它,并将其解析为字节数组,同时对其长度施加无限制

我完成了二进制和十六进制:

public static byte[] GetHexBytes(this string hex, bool preTrimmed = false)
{
    if (!preTrimmed)
    {
        hex = hex.Trim();
        if (hex.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
            hex = hex.Substring(2);
        else if (hex.StartsWith("16#"))
            hex = hex.Substring(3);
    }

    if (hex.Length % 2 != 0) hex = hex.PadLeft(hex.Length + 1, '0');

    return Enumerable.Range(0, hex.Length)
         .Where(x => x % 2 == 0)
         .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
         .ToArray();
}

public static byte[] GetBinaryBytes(this string binary, bool preTrimmed = false)
{
    if (!preTrimmed)
    {
        binary = binary.Trim();
        if (binary.StartsWith("0b", StringComparison.OrdinalIgnoreCase) || binary.StartsWith("2#"))
            binary = binary.Substring(2);
    }

    if (binary.Length % 8 != 0) binary = binary.PadLeft(binary.Length + 8 - binary.Length % 8, '0');

    return Enumerable.Range(0, binary.Length)
         .Where(x => x % 8 == 0)
         .Select(x => Convert.ToByte(binary.Substring(x, 8), 2))
         .ToArray();
}

public static byte[] GetDecimalBytes(this string dec, bool preTrimmed = false)
{
    if (!preTrimmed)
    {
        dec = dec.Trim();
        if (dec.StartsWith("10#"))
            dec = dec.Substring(3);
    }

    //???
}

是否可以以正向方式进行此转换,类似于十六进制和二进制版本(从字符串的开头开始,向前工作)?

如果没有,是否可以以不对字符串长度施加任何限制的方式反向工作,而不使用System.Numerics或BigInteger(从字符串手动执行)?

我希望它能处理任何字符串长度,最大字符串长度为C#(1,073,741,823)。

实施例

"FF".GetHexBytes() => [ 0xFF ]
"11111111".GetBinaryBytes() => [ 0xFF ]
"255".GetDecimalBytes() => [ 0xFF ]

"FFFF".GetHexBytes() => [ 0xFF, 0xFF ]
"1111111111111111".GetBinaryBytes() => [ 0xFF, 0xFF ]
"65535".GetDecimalBytes() => [ 0xFF, 0xFF ]

2 个答案:

答案 0 :(得分:2)

我无法抗拒为这个问题建立一个有点工作的解决方案。但是,正如我已经评论过的那样,直接调用方法有点夸大其词,而且所呈现的代码更具输入性 - 验证效率也不高效。

我的基本方法如下:

  1. 将每个数字转换为基于零的位索引列表,与数字的索引位置相关联
  2. 根据数字位置转换位索引列表
    • 使用过的方法:value * 10 == value * (8 + 2) == (value << 3) + (value << 1)
  3. 通过消除两个相等的索引值并添加其后继值(按位添加)来汇总位索引
  4. 理论上,最后一次应用位加法就足够了,但实际上,需要进行中间压缩以避免大数量的内存异常

    // example input
    string input = "6524562164126412641206685";
    
    var result = input
        // interpret the string as a list of digits with position
        .Reverse()
        // transfer from list of positioned digits to list of actual bit positions,
        // by repeatedly multiplying with 10
        // the resulting bits need to be added for the final result
        .SelectMany((x, i) =>
        {
            // digit value
            var val1 = x - '0';
            var res1 = new List<int>();
            // to bit positions, as if it was the first digit
            for (int j = 0; j < 8; j++)
            {
                if ((val1 & (1 << j)) != 0) res1.Add(j);
            }
            // to absolute bit positions, taking the digit position into account
            for (int j = 1; j <= i; j++)
            {
                var res = new List<int>();
                // multiply by 10, until actual position is reached
                foreach (var item in res1)
                {
                    res.Add(item + 1);
                    res.Add(item + 3);
                }
                // compress bits
                res1 = res.Aggregate(new HashSet<int>(), (set, i1) =>
                    {
                        // two bits in the same position add up to one bit in a higher position
                        while (set.Contains(i1))
                        {
                            set.Remove(i1);
                            i1++;
                        }
                        set.Add(i1);
                        return set;
                    }).ToList();
            }
            return res1;
        }).
        // final elimination of duplicate bit indices
        Aggregate(new HashSet<int>(), (set, i) =>
        {
            while (set.Contains(i))
            {
                set.Remove(i);
                i++;
            }
            set.Add(i);
            return set;
        })
        // transfer bit positions into a byte array - lowest bit is the last bit of the first byte
        .Aggregate(new byte[(long)Math.Ceiling(input.Length / 2.0)], (res, bitpos) =>
        {
            res[bitpos / 8] |= (byte)(1 << (bitpos % 8));
            return res;
        });
    

    实际上,建议将操作拆分为单独的函数,而不是使用这个巨大的linq blob;)

答案 1 :(得分:0)

晚了 5 年,但也许这可能对其他人有所帮助:

public static byte[] GetHexBytes(this string hex)
{
    return BigInteger.Parse(hex, System.Globalization.NumberStyles.HexNumber).ToByteArray(true);
}

public static byte[] GetDecimalBytes(this string dec)
{
     return BigInteger.Parse(dec).ToByteArray(true);
}

// Example:
using System.Numerics;

byte[] inHex = "FFFF".GetHexBytes();      // => [ 0xFF, 0xFF ]
byte[] inDec = "65535".GetDecimalBytes(); // => [ 0xFF, 0xFF ]