Работа с unicode, как избавиться? Android/Java

Я использую библиотеку эмулятора терминала для создания терминала, а затем я использую его для отправки данных, введенных через последовательный порт на последовательное устройство. В библиотеке можно увидеть здесь.

Когда я ввожу данные в терминал, посылается/принимается странная серия символов. Я думаю, что символ замены Юникода отправляется через последовательный порт, серийное устройство не знает, что это такое, и возвращает ~ 0.

Снимок экрана о том, что появляется в терминале, когда я пишу "test": enter image description here

И журнал, показывающий отправленные строки и полученные данные. http://i.imgur.com/x79aPzv.png

Я создаю EmulatorView, это вид терминала. он упоминает алмазы здесь.

private void sendText(CharSequence text) {
                int n = text.length();
                char c;
                try {
                    for(int i = 0; i < n; i++) {
                        c = text.charAt(i);
                        if (Character.isHighSurrogate(c)) {
                            int codePoint;
                            if (++i < n) {
                                codePoint = Character.toCodePoint(c, text.charAt(i));
                            } else {
                                // Unicode Replacement Glyph, aka white question mark in black diamond.
                                codePoint = '\ufffd';
                            }
                            mapAndSend(codePoint);
                        } else {
                            mapAndSend(c);
                        }
                    }
                } catch (IOException e) {
                    Log.e(TAG, "error writing ", e);
                }
            }

Есть ли способ исправить это? Может ли кто-нибудь увидеть в классе библиотеки, почему это происходит? Как я могу ссылаться на в java, чтобы даже разобрать его, если захочу? Я не могу сказать, если (! Str.contains( "" ) я его принимаю.

Когда я набираю терминал, он запускается:

public void write(byte[] bytes, int offset, int count) {


 String str;
try {
    str = new String(bytes, "UTF-8");
      Log.d(TAG, "data received in write: " +str );

      GraphicsTerminalActivity.sendOverSerial(str.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
    Log.d(TAG, "exception" );
    e.printStackTrace();
}

        // appendToEmulator(bytes, 0, bytes.length);

 return;
}

Это то, что я вызываю для отправки данных. sendData (Byte [] data) - это метод библиотеки.

public static void sendOverSerial(byte[] data) {
        String str;
        try {
            str = new String(data,"UTF-8");
             if(mSelectedAdapter !=null && data !=null){
                 Log.d(TAG, "send over serial string==== " + str);

                mSelectedAdapter.sendData(str.getBytes("UTF-8"));
                 }
        } catch (UnsupportedEncodingException e) {
            Log.d(TAG, "exception");
            e.printStackTrace();
        }

    }

Как только данные будут отправлены, ответ будет получен здесь:

public void onDataReceived(int id, byte[] data) {

        try {
            dataReceived = new String(data, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            Log.d(TAG, "exception");
            e.printStackTrace();
        }

        try {
            dataReceivedByte = dataReceived.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            Log.d(TAG, "exception");
            e.printStackTrace();
        }
        statusBool = true;
        Log.d(TAG, "in data received " + dataReceived);
        ((MyBAIsWrapper) bis).renew(data);


        runOnUiThread(new Runnable(){

            @Override
            public void run() {

                mSession.appendToEmulator(dataReceivedByte, 0, dataReceivedByte.length);

            }});

    viewHandler.post(updateView);

}

Соответствующий раздел класса библиотеки, в котором записаны символы:

Соответствующий раздел класса:

private void sendText(CharSequence text) {
                int n = text.length();
                char c;
                try {
                    for(int i = 0; i < n; i++) {
                        c = text.charAt(i);
                        if (Character.isHighSurrogate(c)) {
                            int codePoint;
                            if (++i < n) {
                                codePoint = Character.toCodePoint(c, text.charAt(i));
                            } else {
                                // Unicode Replacement Glyph, aka white question mark in black diamond.
                                codePoint = '\ufffd';
                            }
                            mapAndSend(codePoint);
                        } else {
                            mapAndSend(c);
                        }
                    }
                } catch (IOException e) {
                    Log.e(TAG, "error writing ", e);
                }
            }

            private void mapAndSend(int c) throws IOException {
                int result = mKeyListener.mapControlChar(c);
                if (result < TermKeyListener.KEYCODE_OFFSET) {
                    mTermSession.write(result);
                } else {
                    mKeyListener.handleKeyCode(result - TermKeyListener.KEYCODE_OFFSET, getKeypadApplicationMode());
                }
                clearSpecialKeyStatus();
            }

Ответ 1

Я решил эту проблему, отредактировав библиотеку, которую я использую. Они использовали метод, который преобразовывал байт в int, он принимал codePoint и преобразовывал его. Поэтому для каждого нажатия клавиши используются 4 байта. Я изменил это так, чтобы вместо байта использовался байт. Больше лишних байтов. Ничего не связано с форматом кодирования.

Ответ 2

Java хранит текст внутренне как Unencode Unencode. Используется для 16 бит, теперь я предполагаю это 32 на основании того, что вы получаете четыре символа вывода на своем терминале для каждого символа юникода, который вы пытаетесь вывести.

Что вы, вероятно, захотите сделать, это использовать что-то вроде string.getBytes( "ASCII" ), чтобы преобразовать строку в Юникод в прямое однобайтное ascii. Если ваш эмулятор терминала обрабатывает другие наборы символов (например, Latin-1), используйте вместо "ASCII" .

Затем передайте байты в эмулятор терминала вместо строки.

Примечания: Я не уверен, что "ASCII" - точное имя набора символов; вы захотите исследовать это самостоятельно. Кроме того, я не знаю, что getBytes() будет делать с символами Unicode, которые не могут быть переведены на ascii, поэтому вы также захотите изучить это.

ETA: У меня возникли проблемы с логикой кода из выписок, которые вы опубликовали. Кто называет write(), откуда взялись данные, и куда он идет? Те же вопросы относятся к sendOverSerial() и onDataReceived().

В любом случае, я почти уверен, что где-то, необработанные 32-разрядные данные Unicode были преобразованы в байты без кодирования. С этого момента, отправляя его как есть или перекодируя его, как UTF-8, вы получите эффект, который видите. Я не вижу, как это могло произойти в любом из кода, который вы опубликовали, поэтому я предполагаю, что это произошло где-то еще до того, как вы вызываете какую-либо из функций, которые вы нам показывали.

Ответ 3

Похоже, что библиотека, которую вы используете, отправляет кодовые точки в виде int (которые 32 бит), и ваш код предполагает, что он закодирован как utf-8, который неправильно обрабатывает 4 байта. Это не связано с тем, как Java хранит текст внутри. Btw Java хранит текст внутри, как кодированный UTF-16, а не unencoded unicode. Опять же, это не является причиной этой проблемы. Именно так вы взаимодействуете с библиотекой, которую используете.