Ich habe ein Byte-Array, das mit Hex-Zahlen gefüllt ist, und das einfache Drucken ist ziemlich sinnlos, da es viele nicht druckbare Elemente gibt. Was ich brauche, ist der genaue Hexcode in Form von:3a5f771c
Ich habe ein Byte-Array, das mit Hex-Zahlen gefüllt ist, und das einfache Drucken ist ziemlich sinnlos, da es viele nicht druckbare Elemente gibt. Was ich brauche, ist der genaue Hexcode in Form von:3a5f771c
Antworten:
Aus der Diskussion hier und insbesondere aus dieser Antwort geht hervor, dass dies die Funktion ist, die ich derzeit verwende:
private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
}
return new String(hexChars);
}
Meine eigenen kleinen Benchmarks (eine Million Bytes tausendmal, 256 Bytes zehn Millionen Mal) zeigten, dass es viel schneller ist als jede andere Alternative, ungefähr die Hälfte der Zeit auf langen Arrays. Im Vergleich zu der Antwort, aus der ich sie übernommen habe, konnte durch das Umschalten auf bitweise Operationen - wie in der Diskussion vorgeschlagen - die Zeit für lange Arrays um etwa 20% verkürzt werden. (Bearbeiten: Wenn ich sage, dass es schneller als die Alternativen ist, meine ich den in den Diskussionen angebotenen alternativen Code. Die Leistung entspricht dem Commons Codec, der sehr ähnlichen Code verwendet.)
2k20-Version in Bezug auf Java 9-Kompaktzeichenfolgen:
private static final byte[] HEX_ARRAY = "0123456789ABCDEF".toByteArray();
public static String bytesToHex(byte[] bytes) {
byte[] hexChars = new byte[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
}
return new String(hexChars, StandardCharsets.UTF_8);
}
String printHexBinary(byte[])
und byte[] parseHexBinary(String)
. printHexBinary
ist jedoch viel (2x) langsamer als die Funktion in dieser Antwort. (Ich habe die Quelle überprüft; sie verwendet ein stringBuilder
. parseHexBinary
Verwendet ein Array.) Wirklich, für die meisten Zwecke ist es jedoch schnell genug und Sie haben es wahrscheinlich bereits.
printHexBinary
.
javax.xml.bind.DataTypeConverter
wird aus Java 11 entfernt.
Die Apache Commons Codec- Bibliothek verfügt über eine Hex- Klasse, die genau diese Art von Arbeit erledigt.
import org.apache.commons.codec.binary.Hex;
String foo = "I am a string";
byte[] bytes = foo.getBytes();
System.out.println( Hex.encodeHexString( bytes ) );
import org.apache.commons.codec.*;
Sie könntenimport org.apache.commons.codec.binary.Hex;
org.bouncycastle.util.encoders.Hex
mit dieser Methode:String toHexString(byte[] data)
Die Methode javax.xml.bind.DatatypeConverter.printHexBinary()
, die Teil der Java-Architektur für XML-Bindung (JAXB) ist , war eine bequeme Möglichkeit, eine byte[]
in eine Hex-Zeichenfolge zu konvertieren . Die DatatypeConverter
Klasse enthielt auch viele andere nützliche Datenmanipulationsmethoden.
In Java 8 und früheren Versionen war JAXB Teil der Java-Standardbibliothek. Es wurde als veraltet mit Java 9 und entfernt mit Java 11 , als Teil der Bemühungen , alle Java EE - Pakete in ihre eigenen Bibliotheken zu bewegen. Es ist eine lange Geschichte . Jetzt javax.xml.bind
nicht vorhanden, und wenn Sie JAXB verwenden möchten, das enthält DatatypeConverter
, müssen Sie die JAXB-API und JAXB Runtime von Maven installieren .
Anwendungsbeispiel:
byte bytes[] = {(byte)0, (byte)0, (byte)134, (byte)0, (byte)61};
String hex = javax.xml.bind.DatatypeConverter.printHexBinary(bytes);
Wird darin enden, dass:
000086003D
Diese Antwort ist dieselbe wie diese .
Einfachste Lösung, keine externen Bibliotheken, keine Ziffernkonstanten:
public static String byteArrayToHex(byte[] a) {
StringBuilder sb = new StringBuilder(a.length * 2);
for(byte b: a)
sb.append(String.format("%02x", b));
return sb.toString();
}
Eine Guavenlösung der Vollständigkeit halber:
import com.google.common.io.BaseEncoding;
...
byte[] bytes = "Hello world".getBytes(StandardCharsets.UTF_8);
final String hex = BaseEncoding.base16().lowerCase().encode(bytes);
Jetzt hex
ist "48656c6c6f20776f726c64"
.
new HashCode(bytes).toString()
.
HashCode.fromBytes(checksum).toString()
Dieser einfache Oneliner funktioniert für mich BEARBEITEN
String result = new BigInteger(1, inputBytes).toString(16);
- Wenn Sie diesen verwenden, werden die führenden Nullen entfernt, aber sie haben für meinen Anwendungsfall funktioniert. Vielen Dank an @Voicu für den Hinweis
Hier sind einige gängige Optionen, die von einfach (einzeilig) bis komplex (riesige Bibliothek) geordnet sind. Wenn Sie an Leistung interessiert sind, lesen Sie die folgenden Mikro-Benchmarks.
Eine sehr einfache Lösung ist die Verwendung der BigInteger
Hex-Darstellung:
new BigInteger(1, someByteArray).toString(16)
Da dies Zahlen behandelt, die keine willkürlichen Byte-Strings sind , werden führende Nullen weggelassen - dies kann das sein, was Sie wollen oder nicht (z. B. 000AE3
vs 0AE3
für eine 3-Byte-Eingabe). Dies ist auch sehr langsam, etwa 100x langsamer als bei der nächsten Option.
Hier ist ein voll ausgestattetes, kopierfähiges und einfügbares Code-Snippet, das Groß- / Kleinbuchstaben und Endianness unterstützt . Es ist optimiert, um die Speicherkomplexität zu minimieren und die Leistung zu maximieren, und sollte mit allen modernen Java-Versionen (5+) kompatibel sein.
private static final char[] LOOKUP_TABLE_LOWER = new char[]{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66};
private static final char[] LOOKUP_TABLE_UPPER = new char[]{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46};
public static String encode(byte[] byteArray, boolean upperCase, ByteOrder byteOrder) {
// our output size will be exactly 2x byte-array length
final char[] buffer = new char[byteArray.length * 2];
// choose lower or uppercase lookup table
final char[] lookup = upperCase ? LOOKUP_TABLE_UPPER : LOOKUP_TABLE_LOWER;
int index;
for (int i = 0; i < byteArray.length; i++) {
// for little endian we count from last to first
index = (byteOrder == ByteOrder.BIG_ENDIAN) ? i : byteArray.length - i - 1;
// extract the upper 4 bit and look up char (0-A)
buffer[i << 1] = lookup[(byteArray[index] >> 4) & 0xF];
// extract the lower 4 bit and look up char (0-A)
buffer[(i << 1) + 1] = lookup[(byteArray[index] & 0xF)];
}
return new String(buffer);
}
public static String encode(byte[] byteArray) {
return encode(byteArray, false, ByteOrder.BIG_ENDIAN);
}
Den vollständigen Quellcode mit Apache v2 Lizenz und Decoder finden Sie hier .
Während ich an meinem vorherigen Projekt gearbeitet habe, habe ich dieses kleine Toolkit für die Arbeit mit Bytes in Java erstellt. Es hat keine externen Abhängigkeiten und ist mit Java 7+ kompatibel. Es enthält unter anderem einen sehr schnellen und gut getesteten HEX en / decoder:
import at.favre.lib.bytes.Bytes;
...
Bytes.wrap(someByteArray).encodeHex()
Sie können es auf Github auschecken: bytes-java .
Natürlich gibt es die guten alten Codecs . ( warnende Meinung voraus ) Während ich an dem oben beschriebenen Projekt arbeitete, analysierte ich den Code und war ziemlich enttäuscht. Viele doppelte unorganisierte Codes, veraltete und exotische Codecs sind wahrscheinlich nur für sehr wenige und ziemlich überentwickelte und langsame Implementierungen beliebter Codecs (insbesondere Base64) nützlich. Ich würde daher eine fundierte Entscheidung treffen, wenn Sie es oder eine Alternative verwenden möchten. Wenn Sie es dennoch verwenden möchten, finden Sie hier einen Code-Ausschnitt:
import org.apache.commons.codec.binary.Hex;
...
Hex.encodeHexString(someByteArray));
Meistens haben Sie bereits Guave als Abhängigkeit. Wenn ja, verwenden Sie einfach:
import com.google.common.io.BaseEncoding;
...
BaseEncoding.base16().lowerCase().encode(someByteArray);
Wenn Sie das Spring-Framework mit Spring Security verwenden , können Sie Folgendes verwenden:
import org.springframework.security.crypto.codec.Hex
...
new String(Hex.encode(someByteArray));
Wenn Sie bereits das Sicherheits-Framework Bouncy Castle verwenden , können Sie dessen Hex
util verwenden:
import org.bouncycastle.util.encoders.Hex;
...
Hex.toHexString(someByteArray);
In früheren Java-Versionen (8 und niedriger) war der Java-Code für JAXB als Laufzeitabhängigkeit enthalten. Seit Java 9 und Jigsaw Modularisierung Ihr Code ohne explizite Deklaration nicht auf anderen Code außerhalb seines Moduls zugreifen. Seien Sie sich also bewusst, wenn Sie eine Ausnahme erhalten wie:
java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
beim Ausführen auf einer JVM mit Java 9+. Wenn ja, wechseln Sie die Implementierung zu einer der oben genannten Alternativen. Siehe auch dies Frage .
Hier sind die Ergebnisse eines einfachen JMH- Mikro-Benchmarks, der Byte-Arrays unterschiedlicher Größe codiert . Die Werte sind Operationen pro Sekunde, also ist höher besser. Beachten Sie, dass Mikro-Benchmarks sehr oft kein reales Verhalten darstellen. Nehmen Sie diese Ergebnisse daher mit einem Körnchen Salz.
| Name (ops/s) | 16 byte | 32 byte | 128 byte | 0.95 MB |
|----------------------|-----------:|-----------:|----------:|--------:|
| Opt1: BigInteger | 2,088,514 | 1,008,357 | 133,665 | 4 |
| Opt2/3: Bytes Lib | 20,423,170 | 16,049,841 | 6,685,522 | 825 |
| Opt4: Apache Commons | 17,503,857 | 12,382,018 | 4,319,898 | 529 |
| Opt5: Guava | 10,177,925 | 6,937,833 | 2,094,658 | 257 |
| Opt6: Spring | 18,704,986 | 13,643,374 | 4,904,805 | 601 |
| Opt7: BC | 7,501,666 | 3,674,422 | 1,077,236 | 152 |
| Opt8: JAX-B | 13,497,736 | 8,312,834 | 2,590,940 | 346 |
Technische Daten: JDK 8u202, i7-7700K, Win10, 24 GB RAM. Den vollständigen Benchmark finden Sie hier .
Verwenden Sie die DataTypeConverter-Klassejavax.xml.bind.DataTypeConverter
String hexString = DatatypeConverter.printHexBinary(bytes[] raw);
Ich würde so etwas für feste Länge verwenden, wie Hashes:
md5sum = String.format("%032x", new BigInteger(1, md.digest()));
Ich habe hier drei verschiedene Möglichkeiten gefunden: http://www.rgagnon.com/javadetails/java-0596.html
Das eleganteste, wie er auch bemerkt, denke ich, ist dieses:
static final String HEXES = "0123456789ABCDEF";
public static String getHex( byte [] raw ) {
if ( raw == null ) {
return null;
}
final StringBuilder hex = new StringBuilder( 2 * raw.length );
for ( final byte b : raw ) {
hex.append(HEXES.charAt((b & 0xF0) >> 4))
.append(HEXES.charAt((b & 0x0F)));
}
return hex.toString();
}
if (raw == null) return null
ist nicht schnell ausfallen. Warum würden Sie jemals einen null
Schlüssel verwenden?
Bei den geringen Kosten für das Speichern der Nachschlagetabelle ist diese Implementierung einfach und sehr schnell.
private static final char[] BYTE2HEX=(
"000102030405060708090A0B0C0D0E0F"+
"101112131415161718191A1B1C1D1E1F"+
"202122232425262728292A2B2C2D2E2F"+
"303132333435363738393A3B3C3D3E3F"+
"404142434445464748494A4B4C4D4E4F"+
"505152535455565758595A5B5C5D5E5F"+
"606162636465666768696A6B6C6D6E6F"+
"707172737475767778797A7B7C7D7E7F"+
"808182838485868788898A8B8C8D8E8F"+
"909192939495969798999A9B9C9D9E9F"+
"A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"+
"B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"+
"C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"+
"D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"+
"E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"+
"F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF").toCharArray();
;
public static String getHexString(byte[] bytes) {
final int len=bytes.length;
final char[] chars=new char[len<<1];
int hexIndex;
int idx=0;
int ofs=0;
while (ofs<len) {
hexIndex=(bytes[ofs++] & 0xFF)<<1;
chars[idx++]=BYTE2HEX[hexIndex++];
chars[idx++]=BYTE2HEX[hexIndex];
}
return new String(chars);
}
BYTE2HEX
Array mit einem einfachen for
Zyklus initialisieren ?
static { }
Block zugewiesen werden .
Wie wäre es damit?
String byteToHex(final byte[] hash)
{
Formatter formatter = new Formatter();
for (byte b : hash)
{
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
Ich benutze das lieber:
final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes, int offset, int count) {
char[] hexChars = new char[count * 2];
for ( int j = 0; j < count; j++ ) {
int v = bytes[j+offset] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
Es ist eine etwas flexiblere Anpassung der akzeptierten Antwort. Persönlich behalte ich sowohl die akzeptierte Antwort als auch diese Überlastung bei, die in mehr Kontexten verwendet werden kann.
Normalerweise verwende ich die folgende Methode für die Debuf-Anweisung, aber ich weiß nicht, ob dies der beste Weg ist oder nicht
private static String digits = "0123456789abcdef";
public static String toHex(byte[] data){
StringBuffer buf = new StringBuffer();
for (int i = 0; i != data.length; i++)
{
int v = data[i] & 0xff;
buf.append(digits.charAt(v >> 4));
buf.append(digits.charAt(v & 0xf));
}
return buf.toString();
}
StringBuilder buf = new StringBuilder(data.length * 2);
.
Ok, es gibt eine Reihe von Möglichkeiten, dies zu tun. Wenn Sie sich jedoch für die Verwendung einer Bibliothek entscheiden, würde ich empfehlen, in Ihrem Projekt nachzuschauen, ob in einer Bibliothek, die bereits Teil Ihres Projekts ist, etwas implementiert wurde, bevor Sie eine neue Bibliothek hinzufügen nur um das zu tun. Zum Beispiel, wenn Sie noch nicht haben
org.apache.commons.codec.binary.Hex
Vielleicht hast du ...
org.apache.xerces.impl.dv.util.HexBin
Wenn Sie das Spring Security-Framework verwenden, können Sie Folgendes verwenden:
import org.springframework.security.crypto.codec.Hex
final String testString = "Test String";
final byte[] byteArray = testString.getBytes();
System.out.println(Hex.encode(byteArray));
Das Hinzufügen eines Utility-JAR für einfache Funktionen ist keine gute Option. Stellen Sie stattdessen Ihre eigenen Dienstprogrammklassen zusammen. Folgendes ist eine schnellere Implementierung möglich.
public class ByteHex {
public static int hexToByte(char ch) {
if ('0' <= ch && ch <= '9') return ch - '0';
if ('A' <= ch && ch <= 'F') return ch - 'A' + 10;
if ('a' <= ch && ch <= 'f') return ch - 'a' + 10;
return -1;
}
private static final String[] byteToHexTable = 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"
};
private static final String[] byteToHexTableLowerCase = 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"
};
public static String byteToHex(byte b){
return byteToHexTable[b & 0xFF];
}
public static String byteToHex(byte[] bytes){
if(bytes == null) return null;
StringBuilder sb = new StringBuilder(bytes.length*2);
for(byte b : bytes) sb.append(byteToHexTable[b & 0xFF]);
return sb.toString();
}
public static String byteToHex(short[] bytes){
StringBuilder sb = new StringBuilder(bytes.length*2);
for(short b : bytes) sb.append(byteToHexTable[((byte)b) & 0xFF]);
return sb.toString();
}
public static String byteToHexLowerCase(byte[] bytes){
StringBuilder sb = new StringBuilder(bytes.length*2);
for(byte b : bytes) sb.append(byteToHexTableLowerCase[b & 0xFF]);
return sb.toString();
}
public static byte[] hexToByte(String hexString) {
if(hexString == null) return null;
byte[] byteArray = new byte[hexString.length() / 2];
for (int i = 0; i < hexString.length(); i += 2) {
byteArray[i / 2] = (byte) (hexToByte(hexString.charAt(i)) * 16 + hexToByte(hexString.charAt(i+1)));
}
return byteArray;
}
public static byte hexPairToByte(char ch1, char ch2) {
return (byte) (hexToByte(ch1) * 16 + hexToByte(ch2));
}
}
Eine kleine Variante der von @maybewecouldstealavan vorgeschlagenen Lösung, mit der Sie N Bytes in der Ausgabe-Hex-Zeichenfolge visuell bündeln können:
final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
final static char BUNDLE_SEP = ' ';
public static String bytesToHexString(byte[] bytes, int bundleSize /*[bytes]*/]) {
char[] hexChars = new char[(bytes.length * 2) + (bytes.length / bundleSize)];
for (int j = 0, k = 1; j < bytes.length; j++, k++) {
int v = bytes[j] & 0xFF;
int start = (j * 2) + j/bundleSize;
hexChars[start] = HEX_ARRAY[v >>> 4];
hexChars[start + 1] = HEX_ARRAY[v & 0x0F];
if ((k % bundleSize) == 0) {
hexChars[start + 2] = BUNDLE_SEP;
}
}
return new String(hexChars).trim();
}
Das ist:
bytesToHexString("..DOOM..".toCharArray().getBytes(), 2);
2E2E 444F 4F4D 2E2E
bytesToHexString("..DOOM..".toCharArray().getBytes(), 4);
2E2E444F 4F4D2E2E
Auf dieser Seite kann keine Lösung gefunden werden, die dies nicht tut
Hier ist eine Lösung, die die oben genannten Mängel nicht aufweist (keine Versprechen, meine hat jedoch keine anderen Mängel)
import java.math.BigInteger;
import static java.lang.System.out;
public final class App2 {
// | proposed solution.
public static String encode(byte[] bytes) {
final int length = bytes.length;
// | BigInteger constructor throws if it is given an empty array.
if (length == 0) {
return "00";
}
final int evenLength = (int)(2 * Math.ceil(length / 2.0));
final String format = "%0" + evenLength + "x";
final String result = String.format (format, new BigInteger(bytes));
return result;
}
public static void main(String[] args) throws Exception {
// 00
out.println(encode(new byte[] {}));
// 01
out.println(encode(new byte[] {1}));
//203040
out.println(encode(new byte[] {0x20, 0x30, 0x40}));
// 416c6c20796f75722062617365206172652062656c6f6e6720746f2075732e
out.println(encode("All your base are belong to us.".getBytes()));
}
}
Ich konnte dies nicht unter 62 Opcodes bekommen, aber wenn Sie ohne 0-Auffüllung leben können, falls das erste Byte kleiner als 0x10 ist, dann verwendet die folgende Lösung nur 23 Opcodes. Zeigt wirklich, wie "einfach, sich selbst zu implementieren" -Lösungen wie "Pad mit einer Null, wenn die Zeichenfolgenlänge ungerade ist" ziemlich teuer werden können, wenn eine native Implementierung noch nicht verfügbar ist (oder in diesem Fall, wenn BigInteger die Option hatte, Nullen vorangestellt zu haben toString).
public static String encode(byte[] bytes) {
final int length = bytes.length;
// | BigInteger constructor throws if it is given an empty array.
if (length == 0) {
return "00";
}
return new BigInteger(bytes).toString(16);
}
Meine Lösung basiert auf der Lösung von MaybeWeCouldStealAVan, basiert jedoch nicht auf zusätzlich zugewiesenen Nachschlagetabellen. Es werden keine "int-to-char" -Cast-Hacks verwendet (tatsächlich wird Character.forDigit()
ein Vergleich durchgeführt, um zu überprüfen, was die Ziffer wirklich ist) und daher möglicherweise etwas langsamer. Bitte benutzen Sie es, wo immer Sie wollen. Prost.
public static String bytesToHex(final byte[] bytes)
{
final int numBytes = bytes.length;
final char[] container = new char[numBytes * 2];
for (int i = 0; i < numBytes; i++)
{
final int b = bytes[i] & 0xFF;
container[i * 2] = Character.forDigit(b >>> 4, 0x10);
container[i * 2 + 1] = Character.forDigit(b & 0xF, 0x10);
}
return new String(container);
}
Wenn Sie nach einem genau solchen Byte-Array für Python suchen, habe ich diese Java-Implementierung in Python konvertiert.
class ByteArray:
@classmethod
def char(cls, args=[]):
cls.hexArray = "0123456789ABCDEF".encode('utf-16')
j = 0
length = (cls.hexArray)
if j < length:
v = j & 0xFF
hexChars = [None, None]
hexChars[j * 2] = str( cls.hexArray) + str(v)
hexChars[j * 2 + 1] = str(cls.hexArray) + str(v) + str(0x0F)
# Use if you want...
#hexChars.pop()
return str(hexChars)
array = ByteArray()
print array.char(args=[])
Hier ist eine java.util.Base64
ähnliche Implementierung (teilweise), ist es nicht hübsch?
public class Base16/*a.k.a. Hex*/ {
public static class Encoder{
private static char[] toLowerHex={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
private static char[] toUpperHex={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
private boolean upper;
public Encoder(boolean upper) {
this.upper=upper;
}
public String encode(byte[] data){
char[] value=new char[data.length*2];
char[] toHex=upper?toUpperHex:toLowerHex;
for(int i=0,j=0;i<data.length;i++){
int octet=data[i]&0xFF;
value[j++]=toHex[octet>>4];
value[j++]=toHex[octet&0xF];
}
return new String(value);
}
static final Encoder LOWER=new Encoder(false);
static final Encoder UPPER=new Encoder(true);
}
public static Encoder getEncoder(){
return Encoder.LOWER;
}
public static Encoder getUpperEncoder(){
return Encoder.UPPER;
}
//...
}
private static String bytesToHexString(byte[] bytes, int length) {
if (bytes == null || length == 0) return null;
StringBuilder ret = new StringBuilder(2*length);
for (int i = 0 ; i < length ; i++) {
int b;
b = 0x0f & (bytes[i] >> 4);
ret.append("0123456789abcdef".charAt(b));
b = 0x0f & bytes[i];
ret.append("0123456789abcdef".charAt(b));
}
return ret.toString();
}
Converts bytes data to hex characters
@param bytes byte array to be converted to hex string
@return byte String in hex format
private static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
int v;
for (int j = 0; j < bytes.length; j++) {
v = bytes[j] & 0xFF;
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
}
return new String(hexChars);
}
toHexString(...)
Methode, die helfen kann, wenn Sie danach suchen. AuchString.format(...)
können einige nette Formatierung Tricks tun , um die Verwendung von%2x
Code - String.