Java 问题:将Base64字符串转换为十六进制字符串
TLDR: 我缺少的边缘情况是什么,或者在将Base64字符串转换为十六进制字符串的算法中是否存在错误 我最近决定尝试,但是出于任何原因,我决定尝试编写第一个挑战,而不使用库在十六进制和Base64字符串之间进行转换 我已经成功地将十六进制转换为Base64,但正如您从输出中看到的,当我尝试将Base64转换回十六进制时,有一个轻微的异常(例如,比较Base64到十六进制输出的最后四个值) 十六进制到Base64:Java 问题:将Base64字符串转换为十六进制字符串,java,hex,base64,data-conversion,Java,Hex,Base64,Data Conversion,TLDR: 我缺少的边缘情况是什么,或者在将Base64字符串转换为十六进制字符串的算法中是否存在错误 我最近决定尝试,但是出于任何原因,我决定尝试编写第一个挑战,而不使用库在十六进制和Base64字符串之间进行转换 我已经成功地将十六进制转换为Base64,但正如您从输出中看到的,当我尝试将Base64转换回十六进制时,有一个轻微的异常(例如,比较Base64到十六进制输出的最后四个值) 十六进制到Base64: 应打印:ssdtigtpbgxpbmcgew91cibicmfpibsawtli
应打印:ssdtigtpbgxpbmcgew91cibicmfpibsawtligegcg9pc29ub3vzig11c2hyb29t 实际打印:ssdtigtpbgxpbmcgew91cibicmfpibsawtligegcg9pc29ub3vzig11c2hyb29t Base64到十六进制:
应打印:49276D206B696C6C696E6720726796F757220627261696E206C696B65206120706F69736F6E6F7573206D757368726F6f6d
实际打印:49276D206B696C696E6720727966E717220627261696E206C696B65206120706E697332E6F3573206C717328726F2e6d 我使用来检查我的一些值,假设该站点上的代码是正确的,我的问题似乎是从Base64获取Base10表示,而不是从Base10获取十六进制: 十进制等值 我的输出:
73、39、109、32、107、105、108、108、105、110、103、32、121、110、113、114、32、98、114、97、105、110、32、108、105、107、101、32、97、32、112、110、105、115、46、110、111、53、115、32、108、115、115、114、111、,46,109 站点输出:
73、39、109、32、107、105、108、108、105、110、103、32、121、111、117、114、32、98、114、97、105、110、110、32、108、105、107、101、32、97、32、112、111、105、115、111、110、111、117、115、32、109、115、117、、115、,111,111,109 似乎所有有错误的值都聚集在40-60和100-120之间,但我不确定从那里到底去哪里。我猜我正在处理一些边缘案例,但我不确定那会是什么 相关代码:
private static final Character[] base64Order = new Character[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e',
'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', };
private static final Character[] hexOrder = new Character[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a',
'b', 'c', 'd', 'e', 'f' };
public static String base64ToHex(String base64) throws Exception {
if (base64.length() % 4 != 0 || base64.contains("[^a-zA-Z0-9\\+/]"))
throw new Exception("InputNotBase64");
else {
int charValue = 0;
int index = 0;
String hex = "";
BitSet bits = new BitSet();
for (int i = 0; i < base64.length(); i++) {
charValue = base64.charAt(i);
// get actual value from ASCII table
if (charValue > 64 && charValue < 91)
charValue -= 65;
if (charValue > 96 && charValue < 123)
charValue -= 71;
/// loop that adds to the BitSet reads right-to-left, so reverse
// the bits and then shift
charValue = Integer.reverse(charValue << 24) & 0xff;
charValue >>= 2;
// append binary values to the BitSet
while (charValue != 0L) {
if (charValue % 2 != 0) {
bits.set(index);
}
index++;
charValue >>= 1;
}
// account for trailing 0s
while (index % 6 != 0) {
index++;
}
}
// read 8-bit integer value for hex-value lookup
String temp;
int remainder;
for (int i = 0; i < index; i++) {
charValue = (charValue | (bits.get(i) ? 1 : 0));
if ((i + 1) % 8 == 0) {
temp = "";
while (charValue != 0L) {
remainder = charValue % 16;
temp = hexOrder[remainder] + temp;
charValue /= 16;
}
hex += temp;
}
charValue <<= 1;
}
return hex;
}
}
private static final Character[]base64Order=新字符[]{'A','B','C','D','E','F','G','H','I','J',
‘K’、‘L’、‘M’、‘N’、‘O’、‘P’、‘Q’、‘R’、‘S’、‘T’、‘U’、‘V’、‘W’、‘X’、‘Y’、‘Z’、‘a’、‘b’、‘c’、‘d’、‘e’,
‘f’、‘g’、‘h’、‘i’、‘j’、‘k’、‘l’、‘m’、‘n’、‘o’、‘p’、‘q’、‘r’、‘s’、‘t’、‘u’、‘v’、‘w’、‘x’、‘y’、‘z’,
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', };
私有静态最终字符[]hexOrder=新字符[]{'0','1','2','3','4','5','6','7','8','9','a',',
‘b’、‘c’、‘d’、‘e’、‘f’};
公共静态字符串base64ToHex(字符串base64)引发异常{
如果(base64.length()%4!=0 | | base64.contains(“[^a-zA-Z0-9\\+/]”)
抛出新异常(“InputNotBase64”);
否则{
int charValue=0;
int指数=0;
字符串十六进制=”;
位集位=新位集();
对于(int i=0;i64&&charValue<91)
charValue-=65;
如果(charValue>96&&charValue<123)
charValue-=71;
///添加到位集中的循环从右向左读取,因此反向读取
//先输入位,然后移位
charValue=整数。相反(charValue>=2;
//将二进制值附加到位集
while(charValue!=0L){
如果(字符值%2!=0){
位集(索引);
}
索引++;
charValue>>=1;
}
//跟踪0的帐户
而(索引%6!=0){
索引++;
}
}
//读取用于十六进制值查找的8位整数值
字符串温度;
整数余数;
对于(int i=0;i charValue您忘记了在代码中处理以下字符:“0”、“1”、“2”、“3”、“4”、“5”、“6”、“7”、“8”、“9”、“+”和“/”
如果替换以下代码
if (charValue > 64 && charValue < 91)
charValue -= 65;
if (charValue > 96 && charValue < 123)
charValue -= 71;
在哪里
使用这种方法,我编写的速度比您的
private static String intToHex(int n)
{
return String.valueOf(new char[] { hexOrder[n/16], hexOrder[n%16] });
}
public static String base64ToHexVer2(String base64) throws Exception
{
StringBuilder hex = new StringBuilder(base64.length()*3/4); //capacity could be 3/4 of base64 string length
if (base64.length() % 4 != 0 || base64.contains("[^a-zA-Z0-9\\+/]"))
{
throw new Exception("InputNotBase64");
}
else
{
for (int i = 0; i < base64.length(); i += 4)
{
int n0 = base64ToInt[base64.charAt(i)];
int n1 = base64ToInt[base64.charAt(i+1)];
int n2 = base64ToInt[base64.charAt(i+2)];
int n3 = base64ToInt[base64.charAt(i+3)];
// in descriptions I treat all 64 base chars as 6 bit
// all 6 bites from 0 and 1st 2 from 1st (00000011 ........ ........)
hex.append(intToHex(n0*4 + n1/16));
// last 4 bites from 1st and first 4 from 2nd (........ 11112222 ........)
hex.append(intToHex((n1%16)*16 + n2/4));
// last 2 bites from 2nd and all from 3rd (........ ........ 22333333)
hex.append(intToHex((n2%4)*64 + n3));
}
}
return hex.toString();
}
但这只是一个近似值。当您先检查Ver1,然后再检查Ver2时,结果可能会有点不同。此外,对于不同的Java,结果可能会有所不同(第6、第7、第8)对于用于启动java的不同设置谢谢,没有什么比盯着自己的代码看太久而错过了一些小东西更重要的了。对于获取Base64位置的其他方法,您还有什么其他建议吗?虽然这可能没有多大区别,但遍历数组似乎会增加不必要的时间。我没有考虑使用字母而不是像你提到的“神奇”数字,但这会导致一些奇怪的事情,比如“如果(value>='a'&&value)我的代码有效吗?你的代码在与数字和符号相关的更正后有效吗?我想这两个答案都应该是肯定的:)。如果您想提高性能,可以准备翻译表并使用char作为索引直接获取值。我可以在附加答案中给出它。根据小写字母的幻数,它应该是private static final int indexOfSmallA=26;char
public static int getPositionInBase64(int n)
{
for (int p = 0; p < base64Order.length; p++)
{
if (n == base64Order[p])
{
return p;
}
}
return -1;
}
if (charValue >= 'A' && charValue <= 'Z')
charValue -= 'A';
...
// index = character, value = index of character from base64Order
private static final int[] base64ToInt = new int[128];
public static void initBase64ToIntTable()
{
for (int i = 0; i < base64Order.length; i++)
{
base64ToInt[base64Order[i]] = i;
}
}
charValue = base64ToInt[base64.charAt(i)];
private static String intToHex(int n)
{
return String.valueOf(new char[] { hexOrder[n/16], hexOrder[n%16] });
}
public static String base64ToHexVer2(String base64) throws Exception
{
StringBuilder hex = new StringBuilder(base64.length()*3/4); //capacity could be 3/4 of base64 string length
if (base64.length() % 4 != 0 || base64.contains("[^a-zA-Z0-9\\+/]"))
{
throw new Exception("InputNotBase64");
}
else
{
for (int i = 0; i < base64.length(); i += 4)
{
int n0 = base64ToInt[base64.charAt(i)];
int n1 = base64ToInt[base64.charAt(i+1)];
int n2 = base64ToInt[base64.charAt(i+2)];
int n3 = base64ToInt[base64.charAt(i+3)];
// in descriptions I treat all 64 base chars as 6 bit
// all 6 bites from 0 and 1st 2 from 1st (00000011 ........ ........)
hex.append(intToHex(n0*4 + n1/16));
// last 4 bites from 1st and first 4 from 2nd (........ 11112222 ........)
hex.append(intToHex((n1%16)*16 + n2/4));
// last 2 bites from 2nd and all from 3rd (........ ........ 22333333)
hex.append(intToHex((n2%4)*64 + n3));
}
}
return hex.toString();
}
String b64 = "SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t";
try
{
Base64ToHex.initBase64ToIntTable();
System.out.println(Base64ToHex.base64ToHex(b64));
System.out.println(Base64ToHex.base64ToHexVer2(b64));
int howManyIterations = 100000;
Date start, stop;
long period;
start = new Date();
for (int i = 0; i < howManyIterations; i++)
{
Base64ToHex.base64ToHexVer2(b64);
}
stop = new Date();
period = stop.getTime() - start.getTime();
System.out.println("Ver2 taken " + period + " ms");
start = new Date();
for (int i = 0; i < howManyIterations; i++)
{
Base64ToHex.base64ToHex(b64);
}
stop = new Date();
period = stop.getTime() - start.getTime();
System.out.println("Ver1 taken " + period + " ms");
}
catch (Exception ex)
{
}
49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d
49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d
Ver2 taken 300 ms
Ver1 taken 2080 ms