[英]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 ]
我無法抗拒為這個問題構建一個有點可行的解決方案。 然而,正如我已經評論過的那樣,直接調用該方法有點誇大其詞,並且所提供的代碼更接近輸入驗證,也沒有效率。
我的基本方法如下:
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 ;)
晚了 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.