繁体   English   中英

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

[英]How can I convert a base 10 (decimal) string to an array of bytes _directly_ in C#?

我正在寻找一个可变长度的字符串输入,以数字方式解释它,并将其解析为一个字节数组,同时对其长度没有限制

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

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 ]

我无法抗拒为这个问题构建一个有点可行的解决方案。 然而,正如我已经评论过的那样,直接调用该方法有点夸大其词,并且所提供的代码更接近输入验证,也没有效率。

我的基本方法如下:

  1. 将每个数字转换为一个基于零的位索引列表,与数字的索引位置相关联
  2. 根据数字位置变换位索引列表
    • 使用的方法: value * 10 == value * (8 + 2) == (value << 3) + (value << 1)
  3. 通过消除两个相等的索引值并添加它们的后继值来汇总位索引(按位加法)

理论上,最后应用一次位加法就足够了,但实际上,需要进行中间压缩以避免大量数字出现内存不足异常

// 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 ;)

晚了 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 ]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM