2013-01-15 2 views
10

Eventuali duplicati:
How do you convert Byte Array to Hexadecimal String, and vice versa?La maggior parte della conversione leggera da esadecimale in C#?

ho bisogno di un modo efficiente e veloce per fare questa conversione. Ho provato due modi diversi, ma non sono abbastanza efficienti per me. C'è qualche altro metodo rapido per realizzare questo in tempo reale per un'applicazione con enormi dati?

public byte[] StringToByteArray(string hex) 
    { 
     return Enumerable.Range(0, hex.Length/2).Select(x => Byte.Parse(hex.Substring(2 * x, 2), NumberStyles.HexNumber)).ToArray(); 
    } 

Quanto sopra mi è sembrato più efficiente.

public static byte[] stringTobyte(string hexString) 
    { 
     try 
     { 
      int bytesCount = (hexString.Length)/2; 
      byte[] bytes = new byte[bytesCount]; 
      for (int x = 0; x < bytesCount; ++x) 
      { 
       bytes[x] = Convert.ToByte(hexString.Substring(x * 2, 2), 16); 
      } 
      return bytes; 
     } 
     catch 
     { 
      throw; 
     } 
+3

L'altra domanda, anche se apparentemente sulle conversioni in entrambe le direzioni, finisce incentrata sulla conversione da byte esadecimale. Questa domanda riguarda la migliore conversione nell'altra direzione, quindi FWIW, penso che aggiunga qualcosa. – JasonD

+0

Questo non è sicuramente un duplicato, in quanto fornisce un insieme molto focalizzato di risposte alla domanda specifica fornita –

risposta

3

Presi il codice comparativa dal other question e rielaborato per testare l'esagono metodi bytes qui indicate:

HexToBytesJon: 36979.7 average ticks (over 150 runs) 
HexToBytesJon2: 35886.4 average ticks (over 150 runs) 
HexToBytesJonCiC: 31230.2 average ticks (over 150 runs) 
HexToBytesJase: 15359.1 average ticks (over 150 runs) 

HexToBytesJon è la prima versione di Jon e HexToBytesJon2 è la seconda variante. HexToBytesJonCiC è la versione di Jon con il codice suggerito CodesInChaos. HexToBytesJase è il mio tentativo, sulla base sia sopra ma con conversione nybble alternativa che evita il controllo degli errori, e la ramificazione:

public static byte[] HexToBytesJase(string hexString) 
    { 
     if ((hexString.Length & 1) != 0) 
     { 
      throw new ArgumentException("Input must have even number of characters"); 
     } 
     byte[] ret = new byte[hexString.Length/2]; 
     for (int i = 0; i < ret.Length; i++) 
     { 
      int high = hexString[i*2]; 
      int low = hexString[i*2+1]; 
      high = (high & 0xf) + ((high & 0x40) >> 6) * 9; 
      low = (low & 0xf) + ((low & 0x40) >> 6) * 9; 

      ret[i] = (byte)((high << 4) | low); 
     } 

     return ret; 
    } 
+0

Stranamente, nei miei test, il mio codice è più veloce di quello di Jon, e le due soluzioni di Jon hanno essenzialmente la stessa velocità. Stai correndo senza il debugger allegato? – CodesInChaos

+0

Oops, ero in esecuzione, ma con il debugger. Modificheremo i risultati! – JasonD

+0

Ho anche cambiato 'ParseHex' un po ', rimuovendo' j' e cambiando la condizione di terminazione del ciclo. – CodesInChaos

23

Se davvero bisogno di efficienza, allora:

  • Non creare stringhe
  • non si crea un iteratore

Oppure, e sbarazzarsi di try blocchi che hanno solo un blocco catch che retrocede ... per semplicità invece che per efficienza.

Questa sarebbe una versione abbastanza efficiente:

public static byte[] ParseHex(string hexString) 
{ 
    if ((hexString.Length & 1) != 0) 
    { 
     throw new ArgumentException("Input must have even number of characters"); 
    } 
    int length = hexString.Length/2; 
    byte[] ret = new byte[length]; 
    for (int i = 0, j = 0; i < length; i++) 
    { 
     int high = ParseNybble(hexString[j++]); 
     int low = ParseNybble(hexString[j++]); 
     ret[i] = (byte) ((high << 4) | low); 
    } 

    return ret; 
} 

private static int ParseNybble(char c) 
{ 
    // TODO: Benchmark using if statements instead 
    switch (c) 
    { 
     case '0': case '1': case '2': case '3': case '4': 
     case '5': case '6': case '7': case '8': case '9': 
      return c - '0'; 
     case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 
      return c - ('a' - 10); 
     case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': 
      return c - ('A' - 10); 
     default: 
      throw new ArgumentException("Invalid nybble: " + c); 
    } 
    return c; 
} 

La TODO si riferisce ad un altro come questo. Non ho misurato quale è più veloce.

private static int ParseNybble(char c) 
{ 
    if (c >= '0' && c <= '9') 
    { 
     return c - '0'; 
    } 
    c = (char) (c & ~0x20); 
    if (c >= 'A' && c <= 'F') 
    { 
     return c - ('A' - 10); 
    } 
    throw new ArgumentException("Invalid nybble: " + c); 
} 
+0

@MitchWheat: sospetto di sì - crea un nuovo oggetto stringa per ogni byte. Anche se il GC è piuttosto efficiente, è ancora un lavoro extra che non è richiesto. –

+0

@MitchWheat: aggiungerò un collegamento a questo ... –

+0

@MitchWheat: Grazie - aggiunta la dichiarazione di ritorno. –

4

Come variante di if Jon basato ParseNybble:

public static byte[] ParseHex(string hexString) 
{ 
    if ((hexString.Length & 1) != 0) 
    { 
     throw new ArgumentException("Input must have even number of characters"); 
    } 
    byte[] ret = new byte[hexString.Length/2]; 
    for (int i = 0; i < ret.Length; i++) 
    { 
     int high = ParseNybble(hexString[i*2]); 
     int low = ParseNybble(hexString[i*2+1]); 
     ret[i] = (byte) ((high << 4) | low); 
    } 

    return ret; 
} 

private static int ParseNybble(char c) 
{ 
    unchecked 
    { 
     uint i = (uint)(c - '0'); 
     if(i < 10) 
      return (int)i; 
     i = ((uint)c & ~0x20u) - 'A'; 
     if(i < 6) 
      return (int)i+10; 
     throw new ArgumentException("Invalid nybble: " + c); 
    } 
}