Декодирование base64 до UTF-8, один символ отображается неправильно

Я пытаюсь декодировать строку из base64 в UTF-8 для назначения.

Не программируя Java некоторое время, я, вероятно, не использую самый эффективный метод, однако мне удалось реализовать функцию, работающую на 99% правильно.

Декодирование пример строки в Base64: VGhpcyBpcyBhbiBBcnhhbiBzYW1wbGUgc3RyaW5nIHRoYXQgc2hvdWxkIGJlIGVhc2lseSBkZWNvZGVkIGZyb20gYmFzZTY0LiAgSXQgaW5jbHVkZXMgYSBudW1iZXIgb2YgVVRGOCBjaGFyYWN0ZXJzIHN1Y2ggYXMgdGhlIPEsIOksIOgsIOcgYW5kICYjOTYwOyBjaGFyYWN0ZXJzLg ==

Результаты: Это образец строки Arxan, который должен быть легко декодирован из base64. Он включает в себя несколько символов UTF8, таких как символы ñ, é, è, ç и & # 960.

Однако вместо символа & # 960 должен быть выводимый символ π.

Обратите внимание, что я удалил; после & # 960 здесь, как кажется, Stackru автоматически исправил его до π

Я пробовал много вещей, таких как создание массива байтов и печать этого, но все еще не работает.

Я использую 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 ответ

UTF8 - это кодировка символов, которая преобразует данный символ в 1, 2 или более байтов. Ваш код предполагает, что каждый байт должен быть преобразован в символ. Это прекрасно работает для символов ASCII, таких как a, b, c, которые действительно преобразуются в один байт с помощью UTF8, но не работают для символов, таких как PI, которые преобразуются в многобайтовую последовательность.

Ваш алгоритм ужасно неэффективен, и я бы просто отказался от него и использовал готовый экодер / декодер. JDK 8 поставляется с одним. Гуава и обыкновенный кодек тоже делают. Ваш код должен быть таким простым, как

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);
Другие вопросы по тегам