base64解码为UTF-8,一个字符无法正确显示

时间:2015-10-25 10:37:01

标签: java encoding utf-8 base64 text-decoding

我正在尝试将字符串从base64解码为UTF-8以进行分配。

暂时没有编程Java我可能没有使用最有效的方法,但是我设法实现了99%正确工作的函数。

解码以Base64的例子字符串:的 VGhpcyBpcyBhbiBBcnhhbiBzYW1wbGUgc3RyaW5nIHRoYXQgc2hvdWxkIGJlIGVhc2lseSBkZWNvZGVkIGZyb20gYmFzZTY0LiAgSXQgaW5jbHVkZXMgYSBudW1iZXIgb2YgVVRGOCBjaGFyYWN0ZXJzIHN1Y2ggYXMgdGhlIPEsIOksIOgsIOcgYW5kICYjOTYwOyBjaGFyYWN0ZXJzLg ==

结果: 这是一个Arxan示例字符串,应该可以从base64轻松解码。它包含许多UTF8字符,例如ñ,é,è,ç和&#960字符。

然而,在&#960的位置应该是输出的π符号。

请注意我删除了;在这里看到#960后,Stackoverflow似乎自动将其修正为π

我尝试过很多东西,例如创建一个字节数组并打印它,但仍然没有工作。

我正在使用Eclipse,可能只是那里的输出显示不正确吗?

有人建议让这个工作吗?

谢谢, 文森特

这是我的代码:

package base64;

import java.nio.ByteBuffer;
import java.nio.charset.Charset;

public class Base64 {

    public static void main(String[] args) {
        //Input strings

        String base64 = "VGhpcyBpcyBhbiBBcnhhbiBzYW1wbGUgc3RyaW5nIHRoYXQgc2hvdWxkIGJlIGVhc2lseSBkZWNvZGVkIGZyb20gYmFzZTY0LiAgSXQgaW5jbHVkZXMgYSBudW1iZXIgb2YgVVRGOCBjaGFyYWN0ZXJzIHN1Y2ggYXMgdGhlIPEsIOksIOgsIOcgYW5kICYjOTYwOyBjaGFyYWN0ZXJzLg==";
        //String base64 = "YW55IGNhcm5hbCBwbGVhc3U=";
        String utf8 = "any carnal pleas";

        //Base64 to UTF8
        System.out.println("Base64 conversion to UTF8");
        System.out.println("-------------------------");
        System.out.println("Input base64-string: " + base64);
        System.out.println("Output UTF8-string: " + stringFromBase64(base64));

        System.out.println();       

        //UTF8 to Base64
        System.out.println("UTF8 conversion to base64");
        System.out.println("-------------------------");
        System.out.println("Input UTF8-string: " + utf8);
        System.out.println("Output base64-string: " + stringToBase64(utf8));
        System.out.println();
        System.out.println("Pi is π");

    }

    public static String stringFromBase64(String base64) {
        StringBuilder binary = new StringBuilder();

        int countPadding = countPadding(base64); //count number of padding symbols in source string
        //System.out.println("No of *=* in the input is : " + countPadding);
        //System.out.println(base64);       

        for(int i=0; i<(base64.length()-countPadding); i++)
        {       
            int base64Value = fromBase64(String.valueOf(base64.charAt(i))); //convert Base64 character to Int
            String base64Binary = Integer.toBinaryString(base64Value);  //convert Int to Binary string
            StringBuilder base64BinaryCopy = new StringBuilder(); //debugging

            if (base64Binary.length()<6) //adds required zeros to make 6 bit string
            {           

                for (int j=base64Binary.length();j<6;j++){
                    binary.append("0");
                    base64BinaryCopy.append("0"); //debugging
                }
                base64BinaryCopy.append(base64Binary); // debugging
            } else // debugging
            {
                base64BinaryCopy.append(base64Binary); //debugging

            } // debugging

            //System.out.println(base64.charAt(i) + " = " + base64Value + " = " + base64BinaryCopy); //debugging

            binary.append(base64Binary);            
        }

        //System.out.println(binary);
        //System.out.println(binary.length());


        StringBuilder utf8String = new StringBuilder();


        for (int bytenum=0;bytenum<(binary.length()/8);bytenum++) //parse string Byte-by-Byte
        {
            StringBuilder utf8Bit = new StringBuilder();
            for (int bitnum=0;bitnum<8;bitnum++){
                utf8Bit.append(binary.charAt(bitnum+(bytenum*8)));

            }

            char utf8Char = (char) Integer.parseInt(utf8Bit.toString(), 2); //Byte to utf8 char     
            utf8String.append(String.valueOf(utf8Char)); //utf8 char to string and append to final utf8-string  
            //System.out.println(utf8Bit + " = " + Integer.parseInt(utf8Bit.toString(), 2) + " = " + utf8Char + " = " + utf8String); //debugging
        }                   



        return utf8String.toString();   
    }


    public static String stringToBase64(String utf8) {
        StringBuilder binary = new StringBuilder();
        String paddingString = "";
        String paddingSymbols = "";

        for(int i=0; i<(utf8.length()); i++)
        {       
            int utf8Value = utf8.charAt(i); //convert utf8 character to Int
            String utf8Binary = Integer.toBinaryString(utf8Value);  //convert Int to Binary string
            StringBuilder utf8BinaryCopy = new StringBuilder(); //debugging

            if (utf8Binary.length()<8) //adds required zeros to make 8 bit string
            {           

                for (int j=utf8Binary.length();j<8;j++){
                    binary.append("0");
                    utf8BinaryCopy.append("0"); //debugging
                }
                utf8BinaryCopy.append(utf8Binary); // debugging
            } else // debugging
            {
                utf8BinaryCopy.append(utf8Binary); //debugging

            } // debugging

            //System.out.println(utf8.charAt(i) + " = " + utf8Value + " = " + utf8BinaryCopy);
            binary.append(utf8Binary);

        }

        if ((binary.length() % 6) == 2) {
            paddingString = "0000"; //add 4 padding zeroes
            paddingSymbols = "==";
        } else if ((binary.length() % 6) == 4) {
            paddingString = "00"; //add 2 padding zeroes
            paddingSymbols = "=";
        } 
        binary.append(paddingString); //add padding zeroes

        //System.out.println(binary);
        //System.out.println(binary.length());

        StringBuilder base64String = new StringBuilder();

        for (int bytenum=0;bytenum<(binary.length()/6);bytenum++) //parse string Byte-by-Byte per 6 bits
        {
            StringBuilder base64Bit = new StringBuilder();
            for (int bitnum=0;bitnum<6;bitnum++){
                base64Bit.append(binary.charAt(bitnum+(bytenum*6)));
            }
            int base64Int = Integer.parseInt(base64Bit.toString(), 2); //Byte to Int
            char base64Char = toBase64(base64Int); //Int to Base64 char 
            base64String.append(String.valueOf(base64Char)); //base64 char to string and append to final Base64-string  
            //System.out.println(base64Bit + " = " + base64Int + " = " + base64Char + " = " + base64String); //debugging
        }
        base64String.append(paddingSymbols); //add padding ==
        return base64String.toString(); 

    }

    public static char toBase64(int a) { //converts integer to corresponding base64 char
        String charBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        //charBase64 = new char[]{'A','B','C','D','E','F','G','H','I','J','K','L','M','N'};
        return charBase64.charAt(a);
    }

    public static int fromBase64(String x) { //converts base64 string to corresponding integer
        String charBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        return charBase64.indexOf(x);       
    }

    public static int countPadding(String countPadding) { //counts the number of padding symbols in base64 input string
        int index = countPadding.indexOf("=");
        int count = 0;
        while (index != -1) {
            count++;
            countPadding = countPadding.substring(index + 1);
            index = countPadding.indexOf("=");
        }
        return count;   
    }
}

1 个答案:

答案 0 :(得分:1)

UTF8是一种字符编码,可将给定的char转换为1,2或更多字节。您的代码假定每个字节都应转换为字符。这适用于ASCII字符,例如a,b,c,它们确实被UTF8转换为单个字节,但它不适用于像PI这样转换为多字节序列的字符。

你的算法非常低效,我只是抛弃它并使用现成的ecnoder /解码器。 JDK 8 comes with oneGuavacommons-codec也可以。您的代码应该像

一样简单
String base64EncodedByteArray = "....";
byte[] decodedByteArray = decoder.decode(base64EncodedByteArray);
String asString = new String(decodedByteArray, StandardCharSets.UTF_8);

或者,对于另一个方向:

String someString = "VGhpcyBpcyBhb...";
byte[] asByteArray = someString.getBytes(StandardCharSets.UTF_8);
String base64EncodedByteArray = encoder.encode(asBytArray);