2015-10-25 7 views
0

Я пытаюсь декодировать строку из base64 в UTF-8 для назначения.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 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/"; 
     //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 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/"; 
     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; 
    } 
} 
+0

раскомментировать свой последний оператор отладки в stringFromBase64 (один в "для (INT bytenum = 0;"). Вы увидите вывод, который показывает, что символы «&», «#», «9», «6», «0» выводятся индивидуально. Это означает, что закодированная строка содержит эти символы, а не символ pi. – racraman

+0

Для кодирования/декодировать строку UTF8 правильно, вам, возможно, придется сначала преобразовать строку UTF8 в массив байтов и работать оттуда. – dragon66

+0

Спасибо всем. Я прочитал предложение о байт-массиве где-то, но не смог заставить его работать должным образом. У вас есть предложения, которые были бы замечательными. Как я могу преобразовать свою строку, состоящую из бит в массив байтов? –

ответ

0

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

Ваш алгоритм ужасно неэффективен, и я бы просто отключил его и использовал готовый к использованию ecnoder/decoder. JDK 8 comes with one. Guava и commons-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); 
+0

Спасибо за ваши комментарии, хорошо знать, что символы UTF8 могут состоять из нескольких байтов, я не уверен, хотя как решить это на этом этапе. Истинный мой код очень неэффективен. Это задание, которое меня попросили сделать, и я специально не рассматривал существующие решения (из которых я знал, что они существуют), прежде чем пытаться реализовать это, поскольку это было важно, я сделал это сам. Я не запрограммировал несколько лет, следовательно, неуклюжее решение :) Хотя, если у вас могут быть быстрые подсказки, чтобы сделать код более эффективным, это было бы полезно (без использования стандартных функций). Thanks, Vincent –

+0

Очевидная вещь, которую нужно изменить, состоит в том, чтобы остановить представление байта как строки из 8 символов '1' и '0', но как примитивный 'byte'. –

+0

Какой кодировщик и декодер? –