2015-04-16 2 views
0

Я преобразовываю строку из UTF-8 в CP1047, а затем выполняю на ней шестнадцатеричное кодирование, которое отлично работает. Дальше я делаю конвертирование, используя декодирование шестнадцатеричной строки и отображение ее на консоли в формате UTF-8. Проблема в том, что я не получаю правильную строку, что передал методу кодирования. Ниже приведен фрагмент кода, который я закодирован:String Hex Encoding and Decoding

public class HexEncodeDecode { 

    public static void main(String[] args) throws UnsupportedEncodingException, 
      DecoderException { 
     String reqMsg = "ISO0150000150800C220000080000000040000050000000215102190000000014041615141800001427690161 0B0 00"; 
     char[] hexed = getHex(reqMsg, "UTF-8", "Cp1047"); 

     System.out.println(hexed); 

     System.out.println(getString(hexed)); 
    } 

    public static char[] getHex(String source, String inputCharacterCoding, 
      String outputCharacterCoding) throws UnsupportedEncodingException { 
     return Hex.encodeHex(new String(source.getBytes(inputCharacterCoding), 
       outputCharacterCoding).getBytes(), false); 
    } 

    public static String getString(char[] source) throws DecoderException, 
      UnsupportedEncodingException { 
     return new String(Hex.decodeHex(source), Charset.forName("UTF-8")); 
    } 
} 

выхода я получаю:

C3B1C3AB7CC290C291C295C290C290C290C290C291C295C290C298C290C290C3A41616C290C290C290C290C290C298C290C290C290C290C290C290C290C290C294C290C290C290C290C290C295C290C290C290C290C290C290C29016C291C295C291C29016C291C299C290C290C290C290C290C290C290C290C291C294C290C294C291C296C291C295C291C294C291C298C290C290C290C290C291C2941604C296C299C290C291C296C291C280C290C3A2C290C280C280C280C280C290C290C290C29116C293C294C295C290C290C294C29116C293C294 
ñë|äâ 

Таким образом, нужна помощь в печати входной строки обратно.

Ожидаемый результат будет:

C3B1C3AB7CC290C291C295C290C290C290C290C291C295C290C298C290C290C3A41616C290C290C290C290C290C298C290C290C290C290C290C290C290C290C294C290C290C290C290C290C295C290C290C290C290C290C290C29016C291C295C291C29016C291C299C290C290C290C290C290C290C290C290C291C294C290C294C291C296C291C295C291C294C291C298C290C290C290C290C291C2941604C296C299C290C291C296C291C280C290C3A2C290C280C280C280C280C290C290C290C29116C293C294C295C290C290C294C29116C293C294 
ISO0150000150800C220000080000000040000050000000215102190000000014041615141800001427690161 0B0 00
+1

Показать код 'Hex.encodeHex()'. Кроме того, вы используете '.getBytes()' (второй вызов) без кодировки. – fge

+0

Hex.encodeHex() из библиотеки кодеков apache commons – Arpit

ответ

3
new String(source.getBytes(inputCharacterCoding), outputCharacterCoding) 
    .getBytes() 

Это, вероятно, не делать то, что вы думаете, что он делает.

В первую очередь: a String не имеет кодировки. Повторите за мной: a String не имеет кодировки.

A String - это просто последовательность жетонов, которые предназначены для представления символов. Просто случается, что для этой цели Java использует последовательность char s. Они также могли быть носителями голуби.

UTF8, CP1047 и другие - только кодировки символов; две операции могут быть выполнены:

  • кодирования: превратить поток почтовых голубей (char сек) в поток байтов;
  • декодирование: превратить поток байтов в поток несущих голубей (char).

В принципе, ваше предположение основы неверно; вы не можете связать кодировку с String. Ваш реальный вход должен быть потоком byte (чаще всего это байтовый массив), который, как вам известно, является результатом конкретной кодировки (в вашем случае UTF-8), которую вы хотите перекодировать с помощью другой кодировки (в вашем случае, CP1047).

«Секрет», представляющий реальный ответ здесь, будет кодом вашего метода Hex.encodeHex(), но вы его не показываете, так что это хороший ответ, который я могу собрать.

+0

https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/binary/Hex.html –

+0

@AlastairMcCormack ow .. .Описание самих методов довольно запутывающее:/ – fge

+0

довольно - согласен, это непросто понять при первом чтении :) –

1

Быстрого исправление (хоть немного некрасиво) была бы изменить getString() на:

public static String getString(char[] source) throws DecoderException, UnsupportedEncodingException { 
     return new String(new String(Hex.decodeHex(source), Charset.forName("UTF-8")).getBytes("Cp1047"),"UTF-8"); 
} 

Как FGE уже упоминались, вы переключатель преобразования между символами и байтами, которые являются различными парами обуви. Поэтому в этом быстром решении вы сначала получите hex-декодирование, предполагая UTF-8, затем кодируя его в массив байтов Cp1047 и, наконец, декодируйте его обратно в String с помощью кодировки UTF-8.

Как я уже говорил, это просто быстрое однострочное обходное решение, а не самое чистое решение, поскольку ошибка уже выполняется во время шестнадцатеричной кодировки.

1

reqMsg больше не имеет кодировки, поэтому бессмысленно (и повредить), чтобы попытаться преобразовать, если из UTF-8 в "Cp1047".

Если reqMsg будет поступать из внешнего источника в будущем, например, с диска или сети, тогда вам придется декодировать - возможно, именно здесь возникает путаница. Возможно, вы будете делать: UTF-8-> Unicode (String) -> CP1047-> HEX. Когда вы пишете его на stdout, HEX, скорее всего, будет кодироваться ASCII.

Последующий пример создает ASCII шестнадцатеричную строки, основанную на исходную строку после преобразования в CP1047 (Unicode-> CP1047-> HEX):

String reqMsg = "ISO0150000150800C220000080000000040000050000000215102190000000014041615141800001427690161 0B0 00"; 

    // encode to cp1047 represented as Hex 
    byte[] reqMsqBytes = reqMsg.getBytes("Cp1047"); 
    char[] hex = Hex.encodeHex(reqMsqBytes); 
    System.out.println(hex); 

    // decode 
    String respMsqBytes = new String(Hex.decodeHex(hex), "Cp1047"); 
    System.out.println(respMsqBytes);