ඔබට බයිට් අරා හෙක්සැඩිසිමල් නූලක් බවට පරිවර්තනය කළ හැක්කේ කෙසේද?
ඔබට බයිට් අරා හෙක්සැඩිසිමල් නූලක් බවට පරිවර්තනය කළ හැක්කේ කෙසේද?
Answers:
එක්කෝ:
public static string ByteArrayToString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
හෝ:
public static string ByteArrayToString(byte[] ba)
{
return BitConverter.ToString(ba).Replace("-","");
}
එය සිදු කිරීමේ ඊටත් වඩා ප්රභේද ඇත, උදාහරණයක් ලෙස මෙහි .
ප්රතිලෝම පරිවර්තනය මේ ආකාරයට වනු ඇත:
public static byte[] StringToByteArray(String hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
භාවිතා Substring
කිරීම හොඳම විකල්පය වේ Convert.ToByte
. වැඩි විස්තර සඳහා මෙම පිළිතුර බලන්න . ඔබට වඩා හොඳ කාර්ය සාධනයක් අවශ්ය නම්, ඔබ Convert.ToByte
පහත වැටීමට පෙර වැළකී සිටිය යුතුය SubString
.
සටහන: 2015-08-20 වන විට නව නායකයා.
මම එක් එක් විවිධ පරිවර්තන ක්රම ක්රියාත්මක කළේ කිසියම් ගොරහැඩි Stopwatch
කාර්ය සාධන පරීක්ෂණයක්, අහඹු වාක්යයක් සහිත ධාවනය (n = 61, 1000 පුනරාවර්තන) සහ ව්යාපෘති ගුටන්බර්ග් පා text යක් (n = 1,238,957, 150 පුනරාවර්තන) සමඟ ධාවනය කිරීමෙනි. දළ වශයෙන් වේගවත් සිට මන්දගාමී දක්වා ප්රති results ල මෙන්න. සියලුම මිනුම් කිනිතුල්ලන් තුළ ඇත (කිනිතුල්ලන් 10,000 = 1 එම්එස් ) සහ සියලු සාපේක්ෂ සටහන් [මන්දගාමී] StringBuilder
ක්රියාත්මක කිරීම සමඟ සැසඳේ . භාවිතා කරන කේතය සඳහා, මෙය ක්රියාත්මක කිරීම සඳහා මම දැන් කේතය නඩත්තු කරන පරීක්ෂණ රාමුව නැවත බලන්න .
අවවාදයයි: කොන්ක්රීට් කිසිවක් සඳහා මෙම සංඛ්යාලේඛන මත රඳා නොසිටින්න; ඒවා හුදෙක් නියැදි දත්තවල නියැදි ධාවනයකි. ඔබට සැබවින්ම ඉහළ මට්ටමේ කාර්ය සාධනයක් අවශ්ය නම්, කරුණාකර මෙම ක්රම ඔබේ නිෂ්පාදන අවශ්යතා පිළිබඳ පරිසර නියෝජිතයෙකුගෙන් ඔබ භාවිතා කරන දේ පිළිබඳ දත්ත නියෝජිතයා සමඟ පරීක්ෂා කරන්න.
unsafe
(CodesInChaos හරහා) (විසින් ටෙස්ට් ණයකට එකතු airbreather )
BitConverter
(ටොමලක් හරහා)
{SoapHexBinary}.ToString
(මයික්රොෆ්ට් හරහා)
{byte}.ToString("X2")
(භාවිතා කරමින් foreach
) (විල් ඩීන් ගේ පිළිතුරෙන් උපුටා ගන්නා ලදි)
{byte}.ToString("X2")
(භාවිතා කිරීම {IEnumerable}.Aggregate
සඳහා System.Linq අවශ්ය වේ) (මාර්ක් හරහා)
Array.ConvertAll
(භාවිතා කරමින් string.Join
) (විල් ඩීන් හරහා)
Array.ConvertAll
(භාවිතා කිරීම string.Concat
සඳහා .NET 4.0 අවශ්ය වේ) (විල් ඩීන් හරහා)
{StringBuilder}.AppendFormat
(භාවිතා කරමින් foreach
) (ටොමලක් හරහා)
{StringBuilder}.AppendFormat
(භාවිතා කිරීම {IEnumerable}.Aggregate
සඳහා System.Linq අවශ්ය වේ) (ටොමලක්ගේ පිළිතුරෙන් උපුටා ගන්නා ලදි)
බැලීමේ වගු බයිට් හැසිරවීමට පෙරමුණ ගෙන ඇත. මූලික වශයෙන්, කිසියම් නිබ්ල් හෝ බයිට් හෙක්ස් වල ඇති දේ පූර්ව ගණනය කිරීමේ ක්රමයක් තිබේ. ඉන්පසු, ඔබ දත්ත ඉරා දැමූ විට, ඊළඟ කොටස දෙස බැලීමෙන් එය කුමන හෙක්ස් නූල් දැයි බලන්න. එම අගය පසුව යම් ආකාරයකින් ප්රති string ලය වන නූල් ප්රතිදානයට එකතු වේ. දිගු කලක් තිස්සේ බයිට් හැසිරවීම, සමහර සංවර්ධකයින්ට කියවීමට අපහසු විය හැකි ඉහළම ක්රියාකාරී ප්රවේශය විය.
ඔබගේ හොඳම ඔට්ටුව තවමත් නියෝජිත දත්ත කිහිපයක් සොයාගෙන එය නිෂ්පාදන වැනි පරිසරයක අත්හදා බැලීමට ය. ඔබට වෙනස් මතක සීමාවන් තිබේ නම්, වේගවත් නමුත් වැඩි මතකයක් පරිභෝජනය කරන ක්රමයකට අඩු ප්රතිපාදන සහිත ක්රමයකට ඔබ කැමති විය හැකිය.
මා භාවිතා කළ පරීක්ෂණ කේතය සමඟ සෙල්ලම් කිරීමට නිදහස් වන්න. ඒ අනුවාදය මෙහි ඇතුළත් නමුත් පරිගණක ක්රිඩාවට සමාන නිදහස් හැඟීම වේ ණයකට හා ඔබේ ම ක්රම එකතු කරන්න. ඔබට සිත්ගන්නාසුලු යමක් හමු වුවහොත් හෝ එය භාවිතා කරන පරීක්ෂණ රාමුව වැඩිදියුණු කිරීමට උදව් කිරීමට අවශ්ය නම් කරුණාකර අදින්න ඉල්ලීමක් ඉදිරිපත් කරන්න.
Func<byte[], string>
) /Tests/ConvertByteArrayToHexString/Test.cs වෙත එක් කරන්න.TestCandidates
එම පන්තියේම ප්රතිලාභ අගයට එම ක්රමයේ නම එක් කරන්න .GenerateTestInput
එම පන්තියේම අදහස් ටොගල් කිරීමෙන් ඔබට අවශ්ය ආදාන අනුවාදය, වාක්යය හෝ පෙළ ක්රියාත්මක කරන බවට වග බලා ගන්න .static string ByteArrayToHexStringViaStringJoinArrayConvertAll(byte[] bytes) {
return string.Join(string.Empty, Array.ConvertAll(bytes, b => b.ToString("X2")));
}
static string ByteArrayToHexStringViaStringConcatArrayConvertAll(byte[] bytes) {
return string.Concat(Array.ConvertAll(bytes, b => b.ToString("X2")));
}
static string ByteArrayToHexStringViaBitConverter(byte[] bytes) {
string hex = BitConverter.ToString(bytes);
return hex.Replace("-", "");
}
static string ByteArrayToHexStringViaStringBuilderAggregateByteToString(byte[] bytes) {
return bytes.Aggregate(new StringBuilder(bytes.Length * 2), (sb, b) => sb.Append(b.ToString("X2"))).ToString();
}
static string ByteArrayToHexStringViaStringBuilderForEachByteToString(byte[] bytes) {
StringBuilder hex = new StringBuilder(bytes.Length * 2);
foreach (byte b in bytes)
hex.Append(b.ToString("X2"));
return hex.ToString();
}
static string ByteArrayToHexStringViaStringBuilderAggregateAppendFormat(byte[] bytes) {
return bytes.Aggregate(new StringBuilder(bytes.Length * 2), (sb, b) => sb.AppendFormat("{0:X2}", b)).ToString();
}
static string ByteArrayToHexStringViaStringBuilderForEachAppendFormat(byte[] bytes) {
StringBuilder hex = new StringBuilder(bytes.Length * 2);
foreach (byte b in bytes)
hex.AppendFormat("{0:X2}", b);
return hex.ToString();
}
static string ByteArrayToHexViaByteManipulation(byte[] bytes) {
char[] c = new char[bytes.Length * 2];
byte b;
for (int i = 0; i < bytes.Length; i++) {
b = ((byte)(bytes[i] >> 4));
c[i * 2] = (char)(b > 9 ? b + 0x37 : b + 0x30);
b = ((byte)(bytes[i] & 0xF));
c[i * 2 + 1] = (char)(b > 9 ? b + 0x37 : b + 0x30);
}
return new string(c);
}
static string ByteArrayToHexViaByteManipulation2(byte[] bytes) {
char[] c = new char[bytes.Length * 2];
int b;
for (int i = 0; i < bytes.Length; i++) {
b = bytes[i] >> 4;
c[i * 2] = (char)(55 + b + (((b - 10) >> 31) & -7));
b = bytes[i] & 0xF;
c[i * 2 + 1] = (char)(55 + b + (((b - 10) >> 31) & -7));
}
return new string(c);
}
static string ByteArrayToHexViaSoapHexBinary(byte[] bytes) {
SoapHexBinary soapHexBinary = new SoapHexBinary(bytes);
return soapHexBinary.ToString();
}
static string ByteArrayToHexViaLookupAndShift(byte[] bytes) {
StringBuilder result = new StringBuilder(bytes.Length * 2);
string hexAlphabet = "0123456789ABCDEF";
foreach (byte b in bytes) {
result.Append(hexAlphabet[(int)(b >> 4)]);
result.Append(hexAlphabet[(int)(b & 0xF)]);
}
return result.ToString();
}
static readonly uint* _lookup32UnsafeP = (uint*)GCHandle.Alloc(_Lookup32, GCHandleType.Pinned).AddrOfPinnedObject();
static string ByteArrayToHexViaLookup32UnsafeDirect(byte[] bytes) {
var lookupP = _lookup32UnsafeP;
var result = new string((char)0, bytes.Length * 2);
fixed (byte* bytesP = bytes)
fixed (char* resultP = result) {
uint* resultP2 = (uint*)resultP;
for (int i = 0; i < bytes.Length; i++) {
resultP2[i] = lookupP[bytesP[i]];
}
}
return result;
}
static uint[] _Lookup32 = Enumerable.Range(0, 255).Select(i => {
string s = i.ToString("X2");
return ((uint)s[0]) + ((uint)s[1] << 16);
}).ToArray();
static string ByteArrayToHexViaLookupPerByte(byte[] bytes) {
var result = new char[bytes.Length * 2];
for (int i = 0; i < bytes.Length; i++)
{
var val = _Lookup32[bytes[i]];
result[2*i] = (char)val;
result[2*i + 1] = (char) (val >> 16);
}
return new string(result);
}
static string ByteArrayToHexViaLookup(byte[] bytes) {
string[] hexStringTable = new string[] {
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F",
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F",
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F",
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F",
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F",
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF",
"B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
"C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF",
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF",
"E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
"F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF",
};
StringBuilder result = new StringBuilder(bytes.Length * 2);
foreach (byte b in bytes) {
result.Append(hexStringTable[b]);
}
return result.ToString();
}
විශ්ලේෂණයට වලීඩ්ගේ පිළිතුර එකතු කරන ලදි. ඉතා වේගවත්.
එකතු string.Concat
Array.ConvertAll
සම්පූර්ණත්වය සඳහා ප්රභේද්යයක් (.NET 4.0 අවශ්ය). හා සම string.Join
අනුවාදය.
ටෙස්ට් රෙපෝ වැනි තවත් ප්රභේද ඇතුළත් වේ StringBuilder.Append(b.ToString("X2"))
. කිසිවෙකු ප්රති the ල අවුල් කළේ නැත. foreach
වේගවත් වඩා {IEnumerable}.Aggregate
උදාහරණයක් වශයෙන්, නමුත්, BitConverter
තවමත් ජයග්රහණය කර තිබෙනවා.
SoapHexBinary
විශ්ලේෂණයට මයික්රොෆ්ට්ගේ පිළිතුර එක් කළ අතර එය තෙවන ස්ථානයට පත්විය.
CodesInChaos හි බයිට් හැසිරවීමේ පිළිතුර එකතු කරන ලද අතර එය පළමු ස්ථානය ලබා ගත්තේය (විශාල පෙළ කොටස්වල විශාල ආන්තිකයකින්).
නේතන් මොයින්වසිරිගේ විමසුම් පිළිතුර සහ බ්රයන් ලැම්බර්ට්ගේ බ්ලොග් අඩවියෙන් ප්රභේදය එක් කරන ලදි. දෙකම වේගවත්, නමුත් මා භාවිතා කළ පරීක්ෂණ යන්ත්රයට පෙරමුණ නොගැනීම (AMD Phenom 9750).
@ CodesInChaos හි නව බයිට් මත පදනම් වූ විමසුම් පිළිතුර එක් කරන ලදි. එය වාක්ය පරීක්ෂණ සහ පූර්ණ-පෙළ පරීක්ෂණ යන දෙකටම පෙරමුණ ගෙන ඇති බව පෙනේ.
එකතු airbreather ගේ ප්රතිස්තිකරණය හා unsafe
මේ ප්රභේද්යයක් පිළිතුර ගේ ණයකට . ඔබට අනාරක්ෂිත ක්රීඩාවට ක්රීඩා කිරීමට අවශ්ය නම්, කෙටි නූල් සහ විශාල පෙළ යන දෙකෙහිම පෙර ඕනෑම ජයග්රාහකයෙකුට වඩා විශාල කාර්ය සාධනයක් ලබා ගත හැකිය.
bytes.ToHexStringAtLudicrousSpeed()
).
ඔබට අවශ්ය දේ හරියටම කරන SoapHexBinary නමින් පන්තියක් තිබේ.
using System.Runtime.Remoting.Metadata.W3cXsd2001;
public static byte[] GetStringToBytes(string value)
{
SoapHexBinary shb = SoapHexBinary.Parse(value);
return shb.Value;
}
public static string GetBytesToString(byte[] value)
{
SoapHexBinary shb = new SoapHexBinary(value);
return shb.ToString();
}
ක්රිප්ටෝ කේතය ලිවීමේදී දත්ත මත යැපෙන වේලාවන් පැති නාලිකා ප්රහාරයන්ට තුඩු දිය හැකි බැවින් දත්ත මත යැපෙන ශාඛා සහ වගු බැලීම වළක්වා ගැනීම සාමාන්ය වේ.
එය ද ඉතා වේගවත් ය.
static string ByteToHexBitFiddle(byte[] bytes)
{
char[] c = new char[bytes.Length * 2];
int b;
for (int i = 0; i < bytes.Length; i++) {
b = bytes[i] >> 4;
c[i * 2] = (char)(55 + b + (((b-10)>>31)&-7));
b = bytes[i] & 0xF;
c[i * 2 + 1] = (char)(55 + b + (((b-10)>>31)&-7));
}
return new string(c);
}
Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn
මෙහි ඇතුළු වන්නෙනි, සියලු බලාපොරොත්තු අත්හරින්න
අමුතු බිටු විකාරය පිළිබඳ පැහැදිලි කිරීමක්:
bytes[i] >> 4
බයිට් එකක ඉහළ නිබ්ල් එක bytes[i] & 0xF
නිස්සාරණය කරයිb - 10
< 0
අගයන් සඳහා b < 10
වූ දශම ඉලක්කම් බවට පත් වනු ඇත, >= 0
අගයන් සඳහා b > 10
ලිපියක් බවට පත් වනු ඇත, A
කිරීමට F
.i >> 31
අත්සන් කරන ලද බිට් 32 නිඛිලයක් භාවිතා කිරීමෙන් ලකුණ උපුටා ගනී, අත්සන් දිගුවට ස්තූතියි. එය -1
සඳහා i < 0
සහ 0
සඳහා වනු ඇත i >= 0
.(b-10)>>31
වනු ඇත 0
ලිපි හා -1
ඉලක්කම් සඳහා.0
, සහ b
අප එය සිතියම්ගත කිරීමට අවශ්ය 10 15. පරාසයක වේ A
(65) දක්වා F
(70), 55 එකතු (ගම්ය වන 'A'-10
).b
0 සිට 9 පරාසයේ සිට 0
(48) සිට 9
(57) දක්වා පරාසයට සිතියම් ගත කරයි . මෙයින් අදහස් කරන්නේ එය -7 ( '0' - 55
) බවට පත්විය යුතු බවයි. & -7
බැවින් (0 & -7) == 0
හා (-1 & -7) == -7
.තවත් කරුණු කිහිපයක්:
c
මිනුම් පෙන්වීමෙන් එය ගණනය i
කිරීම ලාභදායී බව පෙන්වන බැවින් මම දර්ශකයට දෙවන ලූප විචල්යයක් භාවිතා නොකළෙමි .i < bytes.Length
ලූපයේ ඉහළ මායිම හරියටම භාවිතා කිරීමෙන් ජිටර්ට සීමාවන් පරීක්ෂා කිරීම ඉවත් කිරීමට ඉඩ සලසයි bytes[i]
, එබැවින් මම එම ප්රභේදය තෝරා ගතිමි.b
එකක් සෑදීමෙන් අනවශ්ය ලෙස පරිවර්තනය කිරීමට සහ බයිට් කිරීමට ඉඩ ලබා දේ.hex string
කිරීමට byte[] array
?
87 + b + (((b-10)>>31)&-39)
byte[] array
", එහි තේරුම බයිට් අරා සමූහයකි, හෝ byte[][]
. මම විනෝද වෙමින් සිටියෙමි.
ඔබට වඩා නම්යශීලී බවක් අවශ්ය නම් BitConverter
, නමුත් 1990 දශකයේ විලාසිතාවේ පැහැදිලි ලූප අවශ්ය නොවන්නේ නම්, ඔබට කළ හැක්කේ:
String.Join(String.Empty, Array.ConvertAll(bytes, x => x.ToString("X2")));
නැතහොත්, ඔබ .NET 4.0 භාවිතා කරන්නේ නම්:
String.Concat(Array.ConvertAll(bytes, x => x.ToString("X2")));
(මුල් ලිපිය පිළිබඳ අදහස් දැක්වීමකින් දෙවැන්න.)
තවත් විමසුම් වගු පදනම් කරගත් ප්රවේශයකි. මෙය එක් එක් බයිටයක් සඳහා එක් බැලීමේ වගුවක් පමණක් භාවිතා කරයි.
private static readonly uint[] _lookup32 = CreateLookup32();
private static uint[] CreateLookup32()
{
var result = new uint[256];
for (int i = 0; i < 256; i++)
{
string s=i.ToString("X2");
result[i] = ((uint)s[0]) + ((uint)s[1] << 16);
}
return result;
}
private static string ByteArrayToHexViaLookup32(byte[] bytes)
{
var lookup32 = _lookup32;
var result = new char[bytes.Length * 2];
for (int i = 0; i < bytes.Length; i++)
{
var val = lookup32[bytes[i]];
result[2*i] = (char)val;
result[2*i + 1] = (char) (val >> 16);
}
return new string(result);
}
ඒ වගේම මම මේ භාවිතා ප්රභේදයන් පරීක්ෂා ushort
, struct{char X1, X2}
, struct{byte X1, X2}
එම විමසුම් වගුවේ.
සම්පාදන ඉලක්කය (x86, X64) මත පදනම්ව, ඒවා දළ වශයෙන් එකම ක්රියාකාරීත්වයක් ඇති හෝ මෙම ප්රභේදයට වඩා තරමක් මන්දගාමී විය.
ඊටත් වඩා ඉහළ කාර්ය සාධනයක් සඳහා, එහි unsafe
සහෝදරයා:
private static readonly uint[] _lookup32Unsafe = CreateLookup32Unsafe();
private static readonly uint* _lookup32UnsafeP = (uint*)GCHandle.Alloc(_lookup32Unsafe,GCHandleType.Pinned).AddrOfPinnedObject();
private static uint[] CreateLookup32Unsafe()
{
var result = new uint[256];
for (int i = 0; i < 256; i++)
{
string s=i.ToString("X2");
if(BitConverter.IsLittleEndian)
result[i] = ((uint)s[0]) + ((uint)s[1] << 16);
else
result[i] = ((uint)s[1]) + ((uint)s[0] << 16);
}
return result;
}
public static string ByteArrayToHexViaLookup32Unsafe(byte[] bytes)
{
var lookupP = _lookup32UnsafeP;
var result = new char[bytes.Length * 2];
fixed(byte* bytesP = bytes)
fixed (char* resultP = result)
{
uint* resultP2 = (uint*)resultP;
for (int i = 0; i < bytes.Length; i++)
{
resultP2[i] = lookupP[bytesP[i]];
}
}
return new string(result);
}
නැතහොත් කෙලින්ම නූලට ලිවීම පිළිගත හැකි යැයි ඔබ සලකන්නේ නම්:
public static string ByteArrayToHexViaLookup32UnsafeDirect(byte[] bytes)
{
var lookupP = _lookup32UnsafeP;
var result = new string((char)0, bytes.Length * 2);
fixed (byte* bytesP = bytes)
fixed (char* resultP = result)
{
uint* resultP2 = (uint*)resultP;
for (int i = 0; i < bytes.Length; i++)
{
resultP2[i] = lookupP[bytesP[i]];
}
}
return result;
}
Span
වෙනුවට දැන් භාවිතා කළ හැකිදැයි මම කල්පනා කරමි unsafe
??
ඔබට BitConverter.ToString ක්රමය භාවිතා කළ හැකිය:
byte[] bytes = {0, 1, 2, 4, 8, 16, 32, 64, 128, 256}
Console.WriteLine( BitConverter.ToString(bytes));
ප්රතිදානය:
00-01-02-04-08-10-20-40-80-එෆ්
වැඩි විස්තර: BitConverter.ToString Method (බයිට් [])
මට අද එකම ගැටලුවකට මුහුණ දීමට සිදු වූ අතර, මෙම කේතය මට හමු විය:
private static string ByteArrayToHex(byte[] barray)
{
char[] c = new char[barray.Length * 2];
byte b;
for (int i = 0; i < barray.Length; ++i)
{
b = ((byte)(barray[i] >> 4));
c[i * 2] = (char)(b > 9 ? b + 0x37 : b + 0x30);
b = ((byte)(barray[i] & 0xF));
c[i * 2 + 1] = (char)(b > 9 ? b + 0x37 : b + 0x30);
}
return new string(c);
}
මූලාශ්රය: ෆෝරම් පෝස්ට් බයිට් [] හෙක්ස් ස්ට්රිං වෙත අරාව (PZahra විසින් පළ කරන ලද ලිපිය බලන්න). 0x උපසර්ගය ඉවත් කිරීම සඳහා මම කේතය ටිකක් වෙනස් කළෙමි.
මම කේතයට යම් කාර්ය සාධන පරීක්ෂණයක් කළ අතර එය BitConverter.ToString () (පැට්රිජ්ගේ තනතුරට අනුව වේගවත්ම) භාවිතා කිරීමට වඩා අට ගුණයකින් වේගවත් විය.
මෙය ටොමලක්ගේ අතිශය ජනප්රිය පිළිතුරේ 4 වන සංශෝධනයට පිළිතුරකි (සහ පසුව කරන ලද සංස්කරණයන්).
මෙම සංස්කරණය වැරදියි කියා මම නඩුව ඉදිරිපත් කර එය ආපසු හැරවිය හැක්කේ මන්දැයි පැහැදිලි කරමි. මඟදී, ඔබට සමහර අභ්යන්තරයන් ගැන යමක් හෝ දෙකක් ඉගෙන ගත හැකි අතර, නොමේරූ ප්රශස්තිකරණය යනු කුමක්ද සහ එය ඔබට දෂ්ට කරන්නේ කෙසේද යන්න පිළිබඳ තවත් උදාහරණයක් බලන්න.
TL; dr: යන්තම් භාවිතා Convert.ToByte
සහ String.Substring
ඔබ ඉක්මන් (පහත "මුල් පිටපත කේතය") ඉන්නේ නම්, එය ඔබ නැවත ක්රියාත්මක කිරීමට අවශ්ය නැති නම්, හොඳම එකතුවක් වේ Convert.ToByte
. Convert.ToByte
ඔබට කාර්ය සාධනය අවශ්ය නම් භාවිතා නොකරන වඩා දියුණු දෙයක් භාවිතා කරන්න (වෙනත් පිළිතුරු බලන්න) . එපා නොවන හැර වෙනත් වෙන කිසිම දෙයක් භාවිතා String.Substring
සංයෝජනය Convert.ToByte
කෙනෙකුට ඇති දෙයක් රසවත් මෙම පිළිතුර අදහස් මේ ගැන කියන්න නොමැති නම් මිස,.
අනතුරු ඇඟවීම: මේ පිළිතුර යල් පැන ගිය එකක් වනු ඇත නම් එය Convert.ToByte(char[], Int32)
අධි බර රාමුව තුළ ක්රියාත්මක වේ. මෙය ඉක්මනින් සිදුවීමට ඉඩක් නැත.
සාමාන්ය රීතියක් ලෙස, “නොමේරූ ලෙස ප්රශස්තිකරණය නොකරන්න” යැයි කීමට මම එතරම් කැමැත්තක් නොදක්වන්නෙමි. ප්රශස්තිකරණය කළ යුතුද නැද්ද යන්න තීරණය කිරීමේදී ඔබ සලකා බැලිය යුතු එකම දෙය නම්: "ප්රශස්තිකරණ ප්රවේශයන් නිසි ලෙස විමර්ශනය කිරීමට මට කාලය හා සම්පත් තිබේද?". ඔබ එසේ නම්, එය ඉතා ඉක්මනින් තියෙන්නේ, ඔබගේ ව්යාපෘතිය තෙක් රැක වඩා පරිණත හෝ ඔබට කාර්ය සාධනය අවශ්ය වන තුරු (සැබෑ අවශ්යතාවක් තිබෙනවා නම්, ඔබ ඇත කිරීමට කාලය). මේ අතර, ඒ වෙනුවට වැඩ කළ හැකි සරලම දේ කරන්න.
මුල් කේතය:
public static byte[] HexadecimalStringToByteArray_Original(string input)
{
var outputLength = input.Length / 2;
var output = new byte[outputLength];
for (var i = 0; i < outputLength; i++)
output[i] = Convert.ToByte(input.Substring(i * 2, 2), 16);
return output;
}
සංශෝධනය 4:
public static byte[] HexadecimalStringToByteArray_Rev4(string input)
{
var outputLength = input.Length / 2;
var output = new byte[outputLength];
using (var sr = new StringReader(input))
{
for (var i = 0; i < outputLength; i++)
output[i] = Convert.ToByte(new string(new char[2] { (char)sr.Read(), (char)sr.Read() }), 16);
}
return output;
}
සංශෝධනය මග හැර ඒ වෙනුවට String.Substring
භාවිතා කරයි StringReader
. දී ඇති හේතුව:
සංස්කරණය කරන්න: තනි පාස් පාර්සර් එකක් භාවිතා කිරීමෙන් ඔබට දිගු නූල් සඳහා කාර්ය සාධනය වැඩි දියුණු කළ හැකිය:
හොඳයි, සඳහා යොමු කේතයString.Substring
දෙස බලන විට , එය පැහැදිලිවම දැනටමත් "තනි පාස්" ය; ඇයි එය එසේ නොවිය යුත්තේ? එය ක්රියාත්මක වන්නේ බයිට් මට්ටමින් මිස අන්වාදේශ යුගල මත නොවේ.
කෙසේ වෙතත් එය නව නූලක් වෙන් කරයි, නමුත් පසුව ඔබට Convert.ToByte
කෙසේ හෝ සමත් වීමට එකක් වෙන් කළ යුතුය . තවද, සංශෝධනයේ දක්වා ඇති විසඳුම සෑම පුනරාවර්තනයක් සඳහාම තවත් වස්තුවක් වෙන් කරයි (ද්වි-වර්ග අරාව); ඔබට එම වෙන් කිරීම ආරක්ෂිතව ලූපයෙන් පිටත තබා එය වළක්වා ගැනීම සඳහා අරාව නැවත භාවිතා කළ හැකිය.
public static byte[] HexadecimalStringToByteArray(string input)
{
var outputLength = input.Length / 2;
var output = new byte[outputLength];
var numeral = new char[2];
using (var sr = new StringReader(input))
{
for (var i = 0; i < outputLength; i++)
{
numeral[0] = (char)sr.Read();
numeral[1] = (char)sr.Read();
output[i] = Convert.ToByte(new string(numeral), 16);
}
}
return output;
}
සෑම ෂඩාස්රාකාරයක්ම numeral
ඉලක්කම් දෙකක් (සංකේත) භාවිතා කරමින් තනි අෂ්ටකයක් නියෝජනය කරයි.
නමුත් එසේ නම්, StringReader.Read
දෙවරක් අමතන්නේ ඇයි? එහි දෙවන අධි භාරය අමතා වර්ග දෙකේ අරාවෙහි අක්ෂර දෙකක් එකවර කියවීමට ඉල්ලා සිටින්න; ඇමතුම් ප්රමාණය දෙකකින් අඩු කරන්න.
public static byte[] HexadecimalStringToByteArray(string input)
{
var outputLength = input.Length / 2;
var output = new byte[outputLength];
var numeral = new char[2];
using (var sr = new StringReader(input))
{
for (var i = 0; i < outputLength; i++)
{
var read = sr.Read(numeral, 0, 2);
Debug.Assert(read == 2);
output[i] = Convert.ToByte(new string(numeral), 16);
}
}
return output;
}
ඔබට ඉතිරිව ඇත්තේ “අගය” එකතු කළ සමාන්තර දර්ශකයක් (අභ්යන්තරය _pos
) වන අතර එය ඔබට ඔබම ප්රකාශ කළ හැකිය ( j
නිදසුනක් ලෙස), අතිරික්ත දිග විචල්යය (අභ්යන්තර _length
) සහ ආදානය පිළිබඳ අතිරික්ත සඳහනක් නූල් (අභ්යන්තර _s
). වෙනත් වචන වලින් කිවහොත්, එය නිෂ් .ල ය.
Read
"කියවන්නේ" කෙසේදැයි ඔබ සිතන්නේ නම්, කේතය දෙස බලන්න , එය කරන්නේ String.CopyTo
ආදාන නූලට ඇමතීම පමණි . ඉතිරිය අපට අවශ්ය නොවන සාරධර්ම පවත්වා ගැනීම සඳහා පොත් තැබීමේ පොදු කාර්යයකි.
එබැවින්, දැනටමත් නූල් කියවනය ඉවත් කර CopyTo
ඔබම අමතන්න ; එය සරල, පැහැදිලි සහ කාර්යක්ෂම වේ.
public static byte[] HexadecimalStringToByteArray(string input)
{
var outputLength = input.Length / 2;
var output = new byte[outputLength];
var numeral = new char[2];
for (int i = 0, j = 0; i < outputLength; i++, j += 2)
{
input.CopyTo(j, numeral, 0, 2);
output[i] = Convert.ToByte(new string(numeral), 16);
}
return output;
}
ඔබට j
සමාන්තරව පියවර දෙකක වර්ධක දර්ශකයක් i
අවශ්යද? ඇත්ත වශයෙන්ම නැත, i
දෙකකින් ගුණ කරන්න (සම්පාදකයාට එකතු කිරීමකට ප්රශස්තිකරණය කළ හැකි).
public static byte[] HexadecimalStringToByteArray_BestEffort(string input)
{
var outputLength = input.Length / 2;
var output = new byte[outputLength];
var numeral = new char[2];
for (int i = 0; i < outputLength; i++)
{
input.CopyTo(i * 2, numeral, 0, 2);
output[i] = Convert.ToByte(new string(numeral), 16);
}
return output;
}
විසඳුම දැන් මොන වගේද? එය ආරම්භයේ දී පමණක් වෙනුවට භාවිතා විය හරියටම වැනි String.Substring
වැල වෙන් කිරීමට සහ ඒ සඳහා දත්ත පිටපත්, ඔබ කිරීමට ෂඩ් දශම ඉලක්කම් පිටපත් කුමන අතරමැදියා අරා භාවිතා කරන්නේ නම් වැල ඔබ වෙන් කිරීම සහ එම දත්ත පිටපත් නැවත සිට අරාව සහ නූලට (ඔබ එය නූල් සාදන්නා තුළ සමත් වූ විට). දෙවන පිටපත දැනටමත් අභ්යන්තර තටාකයේ තිබේ නම් දෙවන පිටපත ප්රශස්තිකරණය කළ හැකි නමුත් String.Substring
මෙම අවස්ථා වලදී එය වළක්වා ගත හැකිය.
ඇත්ත වශයෙන්ම, ඔබ String.Substring
නැවත බැලුවහොත් , එය සාමාන්යයෙන් ඔබට කළ හැකි ප්රමාණයට වඩා වේගයෙන් නූල් වෙන් කිරීම සඳහා නූල් සාදා ඇති ආකාරය පිළිබඳ පහත් මට්ටමේ අභ්යන්තර දැනුමක් භාවිතා කරන බව ඔබට පෙනේ, තවද එය CopyTo
වළක්වා ගැනීම සඳහා කෙලින්ම එහි භාවිතා කරන කේතයම දක්වයි. ඇමතුම ඉහළින්.
String.Substring
අත්පොත ක්රමය
නිගමනය? ඔබට භාවිතා කිරීමට අවශ්ය නම්Convert.ToByte(String, Int32)
(එම ක්රියාකාරිත්වය ඔබම නැවත ක්රියාත්මක කිරීමට ඔබට අවශ්ය නැති නිසා), පරාජය කිරීමට ක්රමයක් නොපෙනේ String.Substring
; ඔබ කරන්නේ රවුමක ධාවනය වන අතර රෝදය නැවත ප්රතිනිර්මාණය කිරීම (උප ප්රශස්ත ද්රව්ය සමඟ පමණි).
ඔබට අතිශය කාර්ය සාධනයක් අවශ්ය නොවන්නේ නම් එය භාවිතා කිරීම Convert.ToByte
සහ String.Substring
වලංගු තේරීමක් බව සලකන්න . මතක තබා ගන්න: විකල්පයක් තෝරා ගන්නේ එය නිසි ලෙස ක්රියාත්මක වන්නේ කෙසේදැයි සොයා බැලීමට ඔබට කාලය හා සම්පත් තිබේ නම් පමණි.
එය තිබුනේ නම් Convert.ToByte(char[], Int32)
, දේවල් ඇත්ත වශයෙන්ම වෙනස් වනු ඇත (මා ඉහත විස්තර කළ දේ කිරීමට සහ සම්පූර්ණයෙන්ම වළක්වා ගැනීමට හැකි වනු ඇත String
).
"මග හැරීමෙන් String.Substring
" වඩා හොඳ කාර්ය සාධනයක් වාර්තා කරන පුද්ගලයින් ද මග හැරෙනු ඇතැයි මම සැක කරමි Convert.ToByte(String, Int32)
, ඔබට කෙසේ හෝ කාර්ය සාධනය අවශ්ය නම් ඔබ සැබවින්ම කළ යුතුය. ඒ සඳහා විවිධ ප්රවේශයන් සොයා ගැනීමට ගණන් කළ නොහැකි වෙනත් පිළිතුරු දෙස බලන්න.
වියාචනය: යොමු මූලාශ්රය යාවත්කාලීන දැයි තහවුරු කර ගැනීම සඳහා මම රාමුවේ නවතම අනුවාදය විසන්ධි කර නැත, මම හිතන්නේ එය එසේ ය.
දැන්, මේ සියල්ල හොඳ සහ තර්කානුකූල යැයි පෙනේ, ඔබ මෙතෙක් දුරට සමත් වී ඇත්දැයි බලාපොරොත්තු විය හැකිය. නමුත් එය සත්යයක්ද?
Intel(R) Core(TM) i7-3720QM CPU @ 2.60GHz
Cores: 8
Current Clock Speed: 2600
Max Clock Speed: 2600
--------------------
Parsing hexadecimal string into an array of bytes
--------------------
HexadecimalStringToByteArray_Original: 7,777.09 average ticks (over 10000 runs), 1.2X
HexadecimalStringToByteArray_BestEffort: 8,550.82 average ticks (over 10000 runs), 1.1X
HexadecimalStringToByteArray_Rev4: 9,218.03 average ticks (over 10000 runs), 1.0X
ඔව්!
බංකුවේ රාමුව සඳහා පාර්ට්රිජ් වෙත මුක්කු, හැක් කිරීම පහසුය. භාවිතා කරන ආදානය පහත දැක්වෙන SHA-1 හෑෂ් බයිට් 100,000 ක් දිග නූලක් සෑදීම සඳහා 5000 වතාවක් පුනරාවර්තනය වේ.
209113288F93A9AB8E474EA78D899AFDBB874355
විනෝද වන්න! (නමුත් මධ්යස්ථව ප්රශස්ත කරන්න.)
@CodesInChaos (ප්රතිලෝම ක්රමය) මගින් පිළිතුරු දීමට අනුපූරකව
public static byte[] HexToByteUsingByteManipulation(string s)
{
byte[] bytes = new byte[s.Length / 2];
for (int i = 0; i < bytes.Length; i++)
{
int hi = s[i*2] - 65;
hi = hi + 10 + ((hi >> 31) & 7);
int lo = s[i*2 + 1] - 65;
lo = lo + 10 + ((lo >> 31) & 7) & 0x0f;
bytes[i] = (byte) (lo | hi << 4);
}
return bytes;
}
පැහැදිලි කිරීම:
& 0x0f
කුඩා අකුරු සඳහා ද සහාය දැක්වීම ය
hi = hi + 10 + ((hi >> 31) & 7);
සමාන වේ:
hi = ch-65 + 10 + (((ch-65) >> 31) & 7);
'0' සඳහා .. '9' යනු එය සමාන hi = ch - 65 + 10 + 7;
වේ hi = ch - 48
(මෙය හේතුව නිසා 0xffffffff & 7
).
'ඒ' සඳහා .. 'එෆ්' යනු එයයි hi = ch - 65 + 10;
(මෙයට හේතුව 0x00000000 & 7
).
'ඒ' .. 'f' අපි ලොකු සංඛ්යා ඇති නිසා අප යම් බිටු කරමින් පෙරනිමි අනුවාදය සිට 32 අඩු කළ යුතුය 0
භාවිතා & 0x0f
.
65 යනු කේතයයි 'A'
48 යනු කේතයයි '0'
7 යනු ASCII වගුව ( ) අතර '9'
සහ අතර ඇති අකුරු ගණනයි .'A'
...456789:;<=>?@ABCD...
බැලීමේ වගුවක් භාවිතා කරමින් මෙම ගැටළුව විසඳා ගත හැකිය. මේ සඳහා එන්කෝඩරය සහ විකේතකය යන දෙකම සඳහා ස්ථිතික මතකය කුඩා ප්රමාණයක් අවශ්ය වේ. කෙසේ වෙතත් මෙම ක්රමය වේගවත් වනු ඇත:
මගේ විසඳුම කේතන වගුව සඳහා බයිට් 1024 ක් ද විකේතනය සඳහා බයිට් 256 ක් ද භාවිතා කරයි.
private static readonly byte[] LookupTable = new byte[] {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
private static byte Lookup(char c)
{
var b = LookupTable[c];
if (b == 255)
throw new IOException("Expected a hex character, got " + c);
return b;
}
public static byte ToByte(char[] chars, int offset)
{
return (byte)(Lookup(chars[offset]) << 4 | Lookup(chars[offset + 1]));
}
private static readonly char[][] LookupTableUpper;
private static readonly char[][] LookupTableLower;
static Hex()
{
LookupTableLower = new char[256][];
LookupTableUpper = new char[256][];
for (var i = 0; i < 256; i++)
{
LookupTableLower[i] = i.ToString("x2").ToCharArray();
LookupTableUpper[i] = i.ToString("X2").ToCharArray();
}
}
public static char[] ToCharLower(byte[] b, int bOffset)
{
return LookupTableLower[b[bOffset]];
}
public static char[] ToCharUpper(byte[] b, int bOffset)
{
return LookupTableUpper[b[bOffset]];
}
StringBuilderToStringFromBytes: 106148
BitConverterToStringFromBytes: 15783
ArrayConvertAllToStringFromBytes: 54290
ByteManipulationToCharArray: 8444
TableBasedToCharArray: 5651 *
* මෙම විසඳුම
විකේතනය කිරීමේදී IOException සහ IndexOutOfRangeException සිදුවිය හැකිය (අක්ෂරයකට වැඩි අගයක් ඇත්නම්> 256). ඩී / කේතන ධාරාවන් හෝ අරා සඳහා ක්රම ක්රියාත්මක කළ යුතුය, මෙය සංකල්පයේ සාක්ෂියක් පමණි.
මෙය විශිෂ්ට තනතුරකි. මම වලීඩ්ගේ විසඳුමට කැමතියි. මම එය පැට්රිජ් පරීක්ෂණයෙන් ධාවනය කර නැති නමුත් එය තරමක් වේගවත් බව පෙනේ. මට ද ආපසු හැරවීමේ ක්රියාවලිය අවශ්ය විය, හෙක්ස් නූලක් බයිට් අරා බවට පරිවර්තනය කිරීම, එබැවින් මම එය ලිව්වේ වලීඩ්ගේ විසඳුමේ ආපසු හැරවීමක් ලෙස ය. එය ටොමලක්ගේ මුල් විසඳුමට වඩා වේගවත් දැයි විශ්වාස නැත. නැවතත්, මම පැට්රිජ්ගේ පරීක්ෂණයෙන් ප්රතිලෝම ක්රියාවලිය ක්රියාත්මක නොකළෙමි.
private byte[] HexStringToByteArray(string hexString)
{
int hexStringLength = hexString.Length;
byte[] b = new byte[hexStringLength / 2];
for (int i = 0; i < hexStringLength; i += 2)
{
int topChar = (hexString[i] > 0x40 ? hexString[i] - 0x37 : hexString[i] - 0x30) << 4;
int bottomChar = hexString[i + 1] > 0x40 ? hexString[i + 1] - 0x37 : hexString[i + 1] - 0x30;
b[i / 2] = Convert.ToByte(topChar + bottomChar);
}
return b;
}
hexString[i] &= ~0x20;
එය සංකීර්ණ කරන්නේ ඇයි? විෂුවල් ස්ටුඩියෝ 2008 හි මෙය සරල ය:
සී #:
string hex = BitConverter.ToString(YourByteArray).Replace("-", "");
VB:
Dim hex As String = BitConverter.ToString(YourByteArray).Replace("-", "")
මෙහි ඇති බොහෝ පිළිතුරු වලට ගොඩගැසීමට නොවේ, නමුත් හෙක්ස් ස්ට්රිං පාර්සර් සෘජුවම ක්රියාත්මක කිරීම සඳහා තරමක් ප්රශස්ත (පිළිගැනීමට වඩා x 4.5x වඩා හොඳ) මට හමු විය. පළමුව, මගේ පරීක්ෂණ වලින් ප්රතිදානය (පළමු කණ්ඩායම මගේ ක්රියාත්මක කිරීම):
Give me that string:
04c63f7842740c77e545bb0b2ade90b384f119f6ab57b680b7aa575a2f40939f
Time to parse 100,000 times: 50.4192 ms
Result as base64: BMY/eEJ0DHflRbsLKt6Qs4TxGfarV7aAt6pXWi9Ak58=
BitConverter'd: 04-C6-3F-78-42-74-0C-77-E5-45-BB-0B-2A-DE-90-B3-84-F1-19-F6-AB-5
7-B6-80-B7-AA-57-5A-2F-40-93-9F
Accepted answer: (StringToByteArray)
Time to parse 100000 times: 233.1264ms
Result as base64: BMY/eEJ0DHflRbsLKt6Qs4TxGfarV7aAt6pXWi9Ak58=
BitConverter'd: 04-C6-3F-78-42-74-0C-77-E5-45-BB-0B-2A-DE-90-B3-84-F1-19-F6-AB-5
7-B6-80-B7-AA-57-5A-2F-40-93-9F
With Mono's implementation:
Time to parse 100000 times: 777.2544ms
Result as base64: BMY/eEJ0DHflRbsLKt6Qs4TxGfarV7aAt6pXWi9Ak58=
BitConverter'd: 04-C6-3F-78-42-74-0C-77-E5-45-BB-0B-2A-DE-90-B3-84-F1-19-F6-AB-5
7-B6-80-B7-AA-57-5A-2F-40-93-9F
With SoapHexBinary:
Time to parse 100000 times: 845.1456ms
Result as base64: BMY/eEJ0DHflRbsLKt6Qs4TxGfarV7aAt6pXWi9Ak58=
BitConverter'd: 04-C6-3F-78-42-74-0C-77-E5-45-BB-0B-2A-DE-90-B3-84-F1-19-F6-AB-5
7-B6-80-B7-AA-57-5A-2F-40-93-9F
නිරවද්යතාවය පරීක්ෂා කිරීම සඳහා base64 සහ 'BitConverter'd' රේඛා තිබේ. ඒවා සමාන බව සලකන්න.
ක්රියාත්මක කිරීම:
public static byte[] ToByteArrayFromHex(string hexString)
{
if (hexString.Length % 2 != 0) throw new ArgumentException("String must have an even length");
var array = new byte[hexString.Length / 2];
for (int i = 0; i < hexString.Length; i += 2)
{
array[i/2] = ByteFromTwoChars(hexString[i], hexString[i + 1]);
}
return array;
}
private static byte ByteFromTwoChars(char p, char p_2)
{
byte ret;
if (p <= '9' && p >= '0')
{
ret = (byte) ((p - '0') << 4);
}
else if (p <= 'f' && p >= 'a')
{
ret = (byte) ((p - 'a' + 10) << 4);
}
else if (p <= 'F' && p >= 'A')
{
ret = (byte) ((p - 'A' + 10) << 4);
} else throw new ArgumentException("Char is not a hex digit: " + p,"p");
if (p_2 <= '9' && p_2 >= '0')
{
ret |= (byte) ((p_2 - '0'));
}
else if (p_2 <= 'f' && p_2 >= 'a')
{
ret |= (byte) ((p_2 - 'a' + 10));
}
else if (p_2 <= 'F' && p_2 >= 'A')
{
ret |= (byte) ((p_2 - 'A' + 10));
} else throw new ArgumentException("Char is not a hex digit: " + p_2, "p_2");
return ret;
}
unsafe
(පැහැදිලිවම අතිරික්ත) අක්ෂර-සිට-නිබ්බල් if
අනුක්රමය වෙනත් ක්රමයකට ගෙනයාමට මම උත්සාහ කළෙමි , නමුත් එය ලබාගත් වේගවත්ම අවස්ථාව මෙයයි.
(මෙය ප්රශ්නයට අඩක් පිළිතුරු සපයන බව මම පිළිගනිමි. වචන-> බයිට් [] පරිවර්තනය අඩුවෙන් නිරූපණය කර ඇති අතර බයිට් [] -> නූල් කෝණය හොඳින් ආවරණය වී ඇති බව පෙනේ. මේ අනුව, මෙම පිළිතුර.)
ආරක්ෂිත අනුවාද:
public static class HexHelper
{
[System.Diagnostics.Contracts.Pure]
public static string ToHex(this byte[] value)
{
if (value == null)
throw new ArgumentNullException("value");
const string hexAlphabet = @"0123456789ABCDEF";
var chars = new char[checked(value.Length * 2)];
unchecked
{
for (int i = 0; i < value.Length; i++)
{
chars[i * 2] = hexAlphabet[value[i] >> 4];
chars[i * 2 + 1] = hexAlphabet[value[i] & 0xF];
}
}
return new string(chars);
}
[System.Diagnostics.Contracts.Pure]
public static byte[] FromHex(this string value)
{
if (value == null)
throw new ArgumentNullException("value");
if (value.Length % 2 != 0)
throw new ArgumentException("Hexadecimal value length must be even.", "value");
unchecked
{
byte[] result = new byte[value.Length / 2];
for (int i = 0; i < result.Length; i++)
{
// 0(48) - 9(57) -> 0 - 9
// A(65) - F(70) -> 10 - 15
int b = value[i * 2]; // High 4 bits.
int val = ((b - '0') + ((('9' - b) >> 31) & -7)) << 4;
b = value[i * 2 + 1]; // Low 4 bits.
val += (b - '0') + ((('9' - b) >> 31) & -7);
result[i] = checked((byte)val);
}
return result;
}
}
}
අනාරක්ෂිත අනුවාදයන් කාර්ය සාධනයට වැඩි කැමැත්තක් දක්වන සහ අනාරක්ෂිතභාවයට බිය නොවන අය සඳහා. ToHex 35% ක් පමණ වේගවත් වන අතර 10% වේගවත් FromHex.
public static class HexUnsafeHelper
{
[System.Diagnostics.Contracts.Pure]
public static unsafe string ToHex(this byte[] value)
{
if (value == null)
throw new ArgumentNullException("value");
const string alphabet = @"0123456789ABCDEF";
string result = new string(' ', checked(value.Length * 2));
fixed (char* alphabetPtr = alphabet)
fixed (char* resultPtr = result)
{
char* ptr = resultPtr;
unchecked
{
for (int i = 0; i < value.Length; i++)
{
*ptr++ = *(alphabetPtr + (value[i] >> 4));
*ptr++ = *(alphabetPtr + (value[i] & 0xF));
}
}
}
return result;
}
[System.Diagnostics.Contracts.Pure]
public static unsafe byte[] FromHex(this string value)
{
if (value == null)
throw new ArgumentNullException("value");
if (value.Length % 2 != 0)
throw new ArgumentException("Hexadecimal value length must be even.", "value");
unchecked
{
byte[] result = new byte[value.Length / 2];
fixed (char* valuePtr = value)
{
char* valPtr = valuePtr;
for (int i = 0; i < result.Length; i++)
{
// 0(48) - 9(57) -> 0 - 9
// A(65) - F(70) -> 10 - 15
int b = *valPtr++; // High 4 bits.
int val = ((b - '0') + ((('9' - b) >> 31) & -7)) << 4;
b = *valPtr++; // Low 4 bits.
val += (b - '0') + ((('9' - b) >> 31) & -7);
result[i] = checked((byte)val);
}
}
return result;
}
}
}
BTW අක්ෂර පරිවර්තනය ආරම්භ කරන සෑම අවස්ථාවකම වැරදි අක්ෂර වින්යාසය ආරම්භ කිරීම සඳහා, අක්ෂර වින්යාසය (නූල් සඳහා) හෝ ස්ථිතික කියවීමට පමණක් (වර්ගය සඳහා) විය යුතුය. අක්ෂර මත පදනම් වූ බයිට් [] නූල් බවට පරිවර්තනය කිරීම බයිට් හැසිරවීමේ අනුවාදයන් තරම් වේගවත් වේ.
ඇත්ත වශයෙන්ම පරීක්ෂණය මුදා හැරීමේදී (ප්රශස්තිකරණය සමඟ) සම්පාදනය කළ යුතු අතර නිදොස් කිරීමේ විකල්පය සමඟ “මර්දනය JIT ප්රශස්තිකරණය” අක්රිය කර ඇත (කේතය නිදොස්කරණය කළ හැකි නම් “මගේ කේතය සක්රීය කරන්න” යන්නට සමාන වේ).
වලීඩ් ඊසා කේතය සඳහා ප්රතිලෝම ශ්රිතය (හයිට්ස් ස්ට්රිං ටු බයිට් අරා):
public static byte[] HexToBytes(this string hexString)
{
byte[] b = new byte[hexString.Length / 2];
char c;
for (int i = 0; i < hexString.Length / 2; i++)
{
c = hexString[i * 2];
b[i] = (byte)((c < 0x40 ? c - 0x30 : (c < 0x47 ? c - 0x37 : c - 0x57)) << 4);
c = hexString[i * 2 + 1];
b[i] += (byte)(c < 0x40 ? c - 0x30 : (c < 0x47 ? c - 0x37 : c - 0x57));
}
return b;
}
කුඩා අකුරු ආධාරයෙන් වලීඩ් ඊසා ක්රියාකාරිත්වය:
public static string BytesToHex(this byte[] barray, bool toLowerCase = true)
{
byte addByte = 0x37;
if (toLowerCase) addByte = 0x57;
char[] c = new char[barray.Length * 2];
byte b;
for (int i = 0; i < barray.Length; ++i)
{
b = ((byte)(barray[i] >> 4));
c[i * 2] = (char)(b > 9 ? b + addByte : b + 0x30);
b = ((byte)(barray[i] & 0xF));
c[i * 2 + 1] = (char)(b > 9 ? b + addByte : b + 0x30);
}
return new string(c);
}
දිගු කිරීමේ ක්රම (වියාචනය: සම්පූර්ණයෙන්ම පරීක්ෂා නොකළ කේතය, BTW ...):
public static class ByteExtensions
{
public static string ToHexString(this byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
{
hex.AppendFormat("{0:x2}", b);
}
return hex.ToString();
}
}
ආදිය. ටොමලක්ගේ විසඳුම් තුනෙන් එකක් භාවිතා කරන්න (අවසාන ක්රමය නූල් මත දිගු කිරීමේ ක්රමයක් වීම).
මයික්රොසොෆ්ට් හි සංවර්ධකයින්ගෙන්, ලස්සන, සරල පරිවර්තනයක්:
public static string ByteArrayToString(byte[] ba)
{
// Concatenate the bytes into one long string
return ba.Aggregate(new StringBuilder(32),
(sb, b) => sb.Append(b.ToString("X2"))
).ToString();
}
ඉහත කරුණු පිරිසිදුව හා සංයුක්තව පැවතුනද, කාර්ය සාධන ජුන්කි ගණන් කරන්නන් භාවිතා කරමින් ඒ ගැන කෑගසනු ඇත. ටොමලක්ගේ මුල් පිළිතුරේ වැඩි දියුණු කළ අනුවාදයක් සමඟ ඔබට උපරිම කාර්ය සාධනය ලබා ගත හැකිය :
public static string ByteArrayToString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
for(int i=0; i < ba.Length; i++) // <-- Use for loop is faster than foreach
hex.Append(ba[i].ToString("X2")); // <-- ToString is faster than AppendFormat
return hex.ToString();
}
මෙතෙක් මා මෙහි පළ කර ඇති සියලුම ක්රියාකාරකම් වලින් වේගවත්ම වේ. ඒ සඳහා මගේ වචනය පමණක් ගන්න එපා ... කාර්ය සාධනය සෑම පුරුද්දක්ම පරීක්ෂා කර එහි CIL කේතය ඔබම පරීක්ෂා කරන්න.
b.ToSting("X2")
.
SQL නූලකට ඇතුළු කිරීම සඳහා (ඔබ විධාන පරාමිතීන් භාවිතා නොකරන්නේ නම්):
public static String ByteArrayToSQLHexString(byte[] Source)
{
return = "0x" + BitConverter.ToString(Source).Replace("-", "");
}
Source == null
හෝ Source.Length == 0
අපිට ප්රශ්නයක් සර්!
වේගය අනුව, මෙය මෙහි ඇති ඕනෑම දෙයකට වඩා හොඳ බව පෙනේ:
public static string ToHexString(byte[] data) {
byte b;
int i, j, k;
int l = data.Length;
char[] r = new char[l * 2];
for (i = 0, j = 0; i < l; ++i) {
b = data[i];
k = b >> 4;
r[j++] = (char)(k > 9 ? k + 0x37 : k + 0x30);
k = b & 15;
r[j++] = (char)(k > 9 ? k + 0x37 : k + 0x30);
}
return new string(r);
}
ඔබ වැඩ කිරීමට යෝජනා කළ කේතය මට ලැබුණේ නැත, ඔලිප්රෝ. hex[i] + hex[i+1]
පෙනෙන විදිහට ආපසු int
.
කෙසේ වෙතත්, වලීඩ්ස් කේතයෙන් ඉඟි කිහිපයක් ගෙන මෙය එකට පහර දීමෙන් මම යම් සාර්ථකත්වයක් ලබා ගතිමි. එය අපායක් මෙන් කැත නමුත් එය මගේ පරීක්ෂණ අනුව අනෙක් අයට සාපේක්ෂව 1/3 වේලාවට වැඩ කරන බව පෙනේ (පැට්රිජ් පරීක්ෂණ යාන්ත්රණය භාවිතා කරමින්). ආදාන ප්රමාණය අනුව. අකුරු වලට වඩා වැඩි සංඛ්යාවක් ඇති බැවින් පළමුව 0-9 වෙන් කිරීම සඳහා:: s වටා මාරුවීම තරමක් වේගවත් ප්රති result ලයක් ලබා දෙනු ඇත.
public static byte[] StringToByteArray2(string hex)
{
byte[] bytes = new byte[hex.Length/2];
int bl = bytes.Length;
for (int i = 0; i < bl; ++i)
{
bytes[i] = (byte)((hex[2 * i] > 'F' ? hex[2 * i] - 0x57 : hex[2 * i] > '9' ? hex[2 * i] - 0x37 : hex[2 * i] - 0x30) << 4);
bytes[i] |= (byte)(hex[2 * i + 1] > 'F' ? hex[2 * i + 1] - 0x57 : hex[2 * i + 1] > '9' ? hex[2 * i + 1] - 0x37 : hex[2 * i + 1] - 0x30);
}
return bytes;
}
ByteArrayToHexViaByteManipulation හි මෙම අනුවාදය වේගවත් විය හැකිය.
මගේ වාර්තා වලින්:
...
static private readonly char[] hexAlphabet = new char[]
{'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
static string ByteArrayToHexViaByteManipulation3(byte[] bytes)
{
char[] c = new char[bytes.Length * 2];
byte b;
for (int i = 0; i < bytes.Length; i++)
{
b = ((byte)(bytes[i] >> 4));
c[i * 2] = hexAlphabet[b];
b = ((byte)(bytes[i] & 0xF));
c[i * 2 + 1] = hexAlphabet[b];
}
return new string(c);
}
මම හිතන්නේ මෙය ප්රශස්තකරණයකි:
static private readonly char[] hexAlphabet = new char[]
{'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
static string ByteArrayToHexViaByteManipulation4(byte[] bytes)
{
char[] c = new char[bytes.Length * 2];
for (int i = 0, ptr = 0; i < bytes.Length; i++, ptr += 2)
{
byte b = bytes[i];
c[ptr] = hexAlphabet[b >> 4];
c[ptr + 1] = hexAlphabet[b & 0xF];
}
return new string(c);
}
ෂඩාස්රාකාර විකේතනය කිරීම සඳහා බිට්-ෆිඩ්ලිං භාවිතා කරන පිළිතුරක් මා සතුව ඇති බැවින් මම මෙම බිට් ෆිඩ්ලිං තරඟයට ඇතුළු වෙමි . ඇමතුම් StringBuilder
ක්රම සඳහාද කාලයක් ගත වන බැවින් අක්ෂර අරා භාවිතා කිරීම ඊටත් වඩා වේගවත් විය හැකි බව සලකන්න .
public static String ToHex (byte[] data)
{
int dataLength = data.Length;
// pre-create the stringbuilder using the length of the data * 2, precisely enough
StringBuilder sb = new StringBuilder (dataLength * 2);
for (int i = 0; i < dataLength; i++) {
int b = data [i];
// check using calculation over bits to see if first tuple is a letter
// isLetter is zero if it is a digit, 1 if it is a letter
int isLetter = (b >> 7) & ((b >> 6) | (b >> 5)) & 1;
// calculate the code using a multiplication to make up the difference between
// a digit character and an alphanumerical character
int code = '0' + ((b >> 4) & 0xF) + isLetter * ('A' - '9' - 1);
// now append the result, after casting the code point to a character
sb.Append ((Char)code);
// do the same with the lower (less significant) tuple
isLetter = (b >> 3) & ((b >> 2) | (b >> 1)) & 1;
code = '0' + (b & 0xF) + isLetter * ('A' - '9' - 1);
sb.Append ((Char)code);
}
return sb.ToString ();
}
public static byte[] FromHex (String hex)
{
// pre-create the array
int resultLength = hex.Length / 2;
byte[] result = new byte[resultLength];
// set validity = 0 (0 = valid, anything else is not valid)
int validity = 0;
int c, isLetter, value, validDigitStruct, validDigit, validLetterStruct, validLetter;
for (int i = 0, hexOffset = 0; i < resultLength; i++, hexOffset += 2) {
c = hex [hexOffset];
// check using calculation over bits to see if first char is a letter
// isLetter is zero if it is a digit, 1 if it is a letter (upper & lowercase)
isLetter = (c >> 6) & 1;
// calculate the tuple value using a multiplication to make up the difference between
// a digit character and an alphanumerical character
// minus 1 for the fact that the letters are not zero based
value = ((c & 0xF) + isLetter * (-1 + 10)) << 4;
// check validity of all the other bits
validity |= c >> 7; // changed to >>, maybe not OK, use UInt?
validDigitStruct = (c & 0x30) ^ 0x30;
validDigit = ((c & 0x8) >> 3) * (c & 0x6);
validity |= (isLetter ^ 1) * (validDigitStruct | validDigit);
validLetterStruct = c & 0x18;
validLetter = (((c - 1) & 0x4) >> 2) * ((c - 1) & 0x2);
validity |= isLetter * (validLetterStruct | validLetter);
// do the same with the lower (less significant) tuple
c = hex [hexOffset + 1];
isLetter = (c >> 6) & 1;
value ^= (c & 0xF) + isLetter * (-1 + 10);
result [i] = (byte)value;
// check validity of all the other bits
validity |= c >> 7; // changed to >>, maybe not OK, use UInt?
validDigitStruct = (c & 0x30) ^ 0x30;
validDigit = ((c & 0x8) >> 3) * (c & 0x6);
validity |= (isLetter ^ 1) * (validDigitStruct | validDigit);
validLetterStruct = c & 0x18;
validLetter = (((c - 1) & 0x4) >> 2) * ((c - 1) & 0x2);
validity |= isLetter * (validLetterStruct | validLetter);
}
if (validity != 0) {
throw new ArgumentException ("Hexadecimal encoding incorrect for input " + hex);
}
return result;
}
ජාවා කේතයෙන් පරිවර්තනය කර ඇත.
Char[]
Char
කාර්ය සාධනය සඳහා මම ඩ්රැෆ්රොසෙන්ස් විසඳුමක් සමඟ යන්නෙමි. විකේතකය සඳහා ඉතා කුඩා ප්රශස්තිකරණයක් වනුයේ "<< 4" ඉවත් කිරීම සඳහා වර්ග සඳහා වගුවක් භාවිතා කිරීමයි.
පැහැදිලිවම ක්රම දෙකේ ඇමතුම් මිල අධිකය. ආදාන හෝ ප්රතිදාන දත්ත මත යම් ආකාරයක චෙක්පතක් සිදු කරන්නේ නම් (සීආර්සී, චෙක්සම් හෝ වෙනත් දෙයක් if (b == 255)...
විය හැකිය) මඟ හැරිය හැකි අතර එමඟින් ක්රමවේදය මුළුමනින්ම කැඳවනු ලැබේ.
භාවිතා offset++
හා offset
වෙනුවට offset
සහ offset + 1
සමහර න්යායික ප්රතිලාභ දෙන්න වෙනවා නමුත් මම මට වඩා මෙම වඩා හොඳ සම්පාදකවරයා මගින් හසුරුවනු පොලිසිය සැක කරයි.
private static readonly byte[] LookupTableLow = new byte[] {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
private static readonly byte[] LookupTableHigh = new byte[] {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
private static byte LookupLow(char c)
{
var b = LookupTableLow[c];
if (b == 255)
throw new IOException("Expected a hex character, got " + c);
return b;
}
private static byte LookupHigh(char c)
{
var b = LookupTableHigh[c];
if (b == 255)
throw new IOException("Expected a hex character, got " + c);
return b;
}
public static byte ToByte(char[] chars, int offset)
{
return (byte)(LookupHigh(chars[offset++]) | LookupLow(chars[offset]));
}
මෙය මගේ හිසට ඉහළින් ඇති අතර එය පරීක්ෂා කර හෝ මිණුම් සලකුණු කර නොමැත.
විවිධත්වය සඳහා තවත් වෙනසක්:
public static byte[] FromHexString(string src)
{
if (String.IsNullOrEmpty(src))
return null;
int index = src.Length;
int sz = index / 2;
if (sz <= 0)
return null;
byte[] rc = new byte[sz];
while (--sz >= 0)
{
char lo = src[--index];
char hi = src[--index];
rc[sz] = (byte)(
(
(hi >= '0' && hi <= '9') ? hi - '0' :
(hi >= 'a' && hi <= 'f') ? hi - 'a' + 10 :
(hi >= 'A' && hi <= 'F') ? hi - 'A' + 10 :
0
)
<< 4 |
(
(lo >= '0' && lo <= '9') ? lo - '0' :
(lo >= 'a' && lo <= 'f') ? lo - 'a' + 10 :
(lo >= 'A' && lo <= 'F') ? lo - 'A' + 10 :
0
)
);
}
return rc;
}
වේගය සඳහා ප්රශස්තිකරණය කර නැත, නමුත් බොහෝ පිළිතුරු වලට වඩා LINQy (.NET 4.0):
<Extension()>
Public Function FromHexToByteArray(hex As String) As Byte()
hex = If(hex, String.Empty)
If hex.Length Mod 2 = 1 Then hex = "0" & hex
Return Enumerable.Range(0, hex.Length \ 2).Select(Function(i) Convert.ToByte(hex.Substring(i * 2, 2), 16)).ToArray
End Function
<Extension()>
Public Function ToHexString(bytes As IEnumerable(Of Byte)) As String
Return String.Concat(bytes.Select(Function(b) b.ToString("X2")))
End Function
නිබ්ල් මෙහෙයුම් දෙක එකකට නැමෙන මාෂප් දෙකක්.
බොහෝ විට කාර්යක්ෂම අනුවාදය:
public static string ByteArrayToString2(byte[] ba)
{
char[] c = new char[ba.Length * 2];
for( int i = 0; i < ba.Length * 2; ++i)
{
byte b = (byte)((ba[i>>1] >> 4*((i&1)^1)) & 0xF);
c[i] = (char)(55 + b + (((b-10)>>31)&-7));
}
return new string( c );
}
බිට්-හැක් කිරීමේ අනුවාදය සහිත පිරිහුණු ලින්ක්:
public static string ByteArrayToString(byte[] ba)
{
return string.Concat( ba.SelectMany( b => new int[] { b >> 4, b & 0xF }).Select( b => (char)(55 + b + (((b-10)>>31)&-7))) );
}
සහ ආපසු හැරවීම:
public static byte[] HexStringToByteArray( string s )
{
byte[] ab = new byte[s.Length>>1];
for( int i = 0; i < s.Length; i++ )
{
int b = s[i];
b = (b - '0') + ((('9' - b)>>31)&-7);
ab[i>>1] |= (byte)(b << 4*((i&1)^1));
}
return ab;
}
තවත් ක්රමයක් නම් stackalloc
GC මතක පීඩනය අඩු කිරීම සඳහා භාවිතා කිරීමයි:
static string ByteToHexBitFiddle(byte[] bytes)
{
var c = stackalloc char[bytes.Length * 2 + 1];
int b;
for (int i = 0; i < bytes.Length; ++i)
{
b = bytes[i] >> 4;
c[i * 2] = (char)(55 + b + (((b - 10) >> 31) & -7));
b = bytes[i] & 0xF;
c[i * 2 + 1] = (char)(55 + b + (((b - 10) >> 31) & -7));
}
c[bytes.Length * 2 ] = '\0';
return new string(c);
}
මෙන්න මගේ වෙඩි පහර. නූල් සහ බයිට් දිගු කිරීම සඳහා මම දිගු පන්ති යුගලයක් නිර්මාණය කර ඇත්තෙමි. විශාල ගොනු පරීක්ෂණයකදී, කාර්ය සාධනය බයිට් හැසිරවීම 2 සමඟ සැසඳිය හැකිය.
ToHexString සඳහා පහත කේතය යනු බැලීමේ සහ මාරුවීමේ ඇල්ගොරිතම ප්රශස්ත ලෙස ක්රියාත්මක කිරීමයි. එය බෙහ්රූස්ගේ කතාවට බොහෝ දුරට සමාන ය, නමුත් එය නැවත භාවිතා foreach
කිරීමට භාවිතා කරන අතර කවුන්ටරය පැහැදිලිවම සුචිගත කිරීමට වඩා වේගවත් වේ for
.
එය මගේ යන්ත්රයේ බයිට් හැසිරවීම 2 ට පිටුපසින් 2 වන ස්ථානයට පැමිණ ඇති අතර එය ඉතා පහසුවෙන් කියවිය හැකි කේතයකි. පහත දැක්වෙන පරීක්ෂණ ප්රති results ල ද උනන්දුවක් දක්වයි:
ToHexStringCharArrayWithCharArrayLookup: සාමාන්ය කිනිතුල්ලන් 41,589.69 ක් (ලකුණු 1000 ට වැඩි), 1.5X ToHexStringCharArrayWithStringLookup: 50,764.06 සාමාන්ය කිනිතුල්ලන් (ලකුණු 1000 ට වැඩි), 1.2X ToHexStringStringCoringerUper2
ඉහත ප්රති results ල මත පදනම්ව එය නිගමනය කිරීම ආරක්ෂිත බව පෙනේ:
මෙන්න කේතය:
using System;
namespace ConversionExtensions
{
public static class ByteArrayExtensions
{
private readonly static char[] digits = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
public static string ToHexString(this byte[] bytes)
{
char[] hex = new char[bytes.Length * 2];
int index = 0;
foreach (byte b in bytes)
{
hex[index++] = digits[b >> 4];
hex[index++] = digits[b & 0x0F];
}
return new string(hex);
}
}
}
using System;
using System.IO;
namespace ConversionExtensions
{
public static class StringExtensions
{
public static byte[] ToBytes(this string hexString)
{
if (!string.IsNullOrEmpty(hexString) && hexString.Length % 2 != 0)
{
throw new FormatException("Hexadecimal string must not be empty and must contain an even number of digits to be valid.");
}
hexString = hexString.ToUpperInvariant();
byte[] data = new byte[hexString.Length / 2];
for (int index = 0; index < hexString.Length; index += 2)
{
int highDigitValue = hexString[index] <= '9' ? hexString[index] - '0' : hexString[index] - 'A' + 10;
int lowDigitValue = hexString[index + 1] <= '9' ? hexString[index + 1] - '0' : hexString[index + 1] - 'A' + 10;
if (highDigitValue < 0 || lowDigitValue < 0 || highDigitValue > 15 || lowDigitValue > 15)
{
throw new FormatException("An invalid digit was encountered. Valid hexadecimal digits are 0-9 and A-F.");
}
else
{
byte value = (byte)((highDigitValue << 4) | (lowDigitValue & 0x0F));
data[index / 2] = value;
}
}
return data;
}
}
}
මගේ කේතය @ පැට්රිජ්ගේ පරීක්ෂණ ව්යාපෘතියට මගේ යන්ත්රය මත තැබූ විට මට ලැබුණු පරීක්ෂණ ප්රති results ල පහත දැක්වේ. මම ෂඩාස්රාකාරයෙන් බයිට් අරා බවට පරිවර්තනය කිරීම සඳහා පරීක්ෂණයක් ද එක් කළෙමි. මගේ කේතය ක්රියාත්මක කළ පරීක්ෂණ ලකුණු වන්නේ බයිට්ආරේටෝහෙක්ස්වියා ඔප්ටිමයිස්ලූකප් ඇන්ඩ්ෂිෆ්ට් සහ හෙක්ස්ටෝබයිට්ආරේ වීවාබයිට් මැනුපියුලේෂන් ය. HexToByteArrayViaConvertToByte XXXX වෙතින් ලබාගෙන ඇත. HexToByteArrayViaSoapHexBinary යනු @ මයික්රොෆ්ට්ගේ පිළිතුරෙන්.
Intel Pentium III Xeon ප්රොසෙසරය
Cores: 4 <br/> Current Clock Speed: 1576 <br/> Max Clock Speed: 3092 <br/>
බයිට් සමූහය ෂඩාස්රාකාර නූල් නිරූපණය බවට පරිවර්තනය කිරීම
ByteArrayToHexViaByteManipulation2: 39,366.64 සාමාන්ය කිනිතුල්ලන් (ලකුණු 1000 ට වැඩි), 22.4X
ByteArrayToHexViaOptimizedLookupAndShift: සාමාන්ය කිනිතුල්ලන් 41,588.64 (ලකුණු 1000 ට වැඩි), 21.2X
ByteArrayToHexViaLookup: සාමාන්ය කිනිතුල්ලන් 55,509.56 (ලකුණු 1000 ට වැඩි), 15.9X
ByteArrayToHexViaByteManipulation: සාමාන්ය කිනිතුල්ලන් 65,349.12 (ලකුණු 1000 ට වැඩි), 13.5X
ByteArrayToHexViaLookupAndShift: සාමාන්ය කිනිතුල්ලන් 86,926.87 (ලකුණු 1000 ට වැඩි), 10.2X
ByteArrayToHexStringViaBitConverter: සාමාන්ය කිනිතුල්ලන් 139,353.73 (ලකුණු 1000 ට වැඩි), 6.3X
ByteArrayToHexViaSoapHexBinary: 314,598.77 සාමාන්ය කිනිතුල්ලන් (ලකුණු 1000 ට වැඩි), 2.8X
ByteArrayToHexStringViaStringBuilderForEachByteToString: 344,264.63 සාමාන්ය කිනිතුල්ලන් (ලකුණු 1000 ට වැඩි), 2.6X
ByteArrayToHexStringViaStringBuilderAggregateByteToString: 382,623.44 සාමාන්ය කිනිතුල්ලන් (ලකුණු 1000 ට වැඩි), 2.3X
ByteArrayToHexStringViaStringBuilderForEachAppendFormat: 818,111.95 සාමාන්ය කිනිතුල්ලන් (ලකුණු 1000 ට වැඩි), 1.1X
ByteArrayToHexStringViaStringConcatArrayConvertAll: 839,244.84 සාමාන්ය කිනිතුල්ලන් (ලකුණු 1000 ට වැඩි), 1.1X
ByteArrayToHexStringViaStringBuilderAggregateAppendFormat: 867,303.98 සාමාන්ය කිනිතුල්ලන් (ලකුණු 1000 ට වැඩි), 1.0X
ByteArrayToHexStringViaStringJoinArrayConvertAll: 882,710.28 සාමාන්ය කිනිතුල්ලන් (ලකුණු 1000 ට වැඩි), 1.0X
තවත් වේගවත් කාර්යයක් ...
private static readonly byte[] HexNibble = new byte[] {
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
0x8, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF
};
public static byte[] HexStringToByteArray( string str )
{
int byteCount = str.Length >> 1;
byte[] result = new byte[byteCount + (str.Length & 1)];
for( int i = 0; i < byteCount; i++ )
result[i] = (byte) (HexNibble[str[i << 1] - 48] << 4 | HexNibble[str[(i << 1) + 1] - 48]);
if( (str.Length & 1) != 0 )
result[byteCount] = (byte) HexNibble[str[str.Length - 1] - 48];
return result;
}