我希望获取一个可变长度的字符串输入,以数字方式解释它,并将其解析为字节数组,同时对其长度施加无限制。
我完成了二进制和十六进制:
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 ]
答案 0 :(得分:2)
我无法抗拒为这个问题建立一个有点工作的解决方案。但是,正如我已经评论过的那样,直接调用方法有点夸大其词,而且所呈现的代码更具输入性 - 验证效率也不高效。
我的基本方法如下:
value * 10 == value * (8 + 2) == (value << 3) + (value << 1)
理论上,最后一次应用位加法就足够了,但实际上,需要进行中间压缩以避免大数量的内存异常
// 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 ]