Имея дело с unicode �, как избавиться? Android / java

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

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

скриншот того, что отображается в терминале, когда я пишу "тест": 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, чтобы даже разобрать его, если бы я хотел? Я не могу сказать, если (!ул.содержит ( " � " ) Я беру его.

когда я набираю терминал это работает:

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();
            }

3 ответов


Java хранит текст внутри как unencoded Unicode. Раньше было 16 бит, теперь я предполагаю, что это 32, основываясь на том факте, что вы получаете четыре символа вывода на своем терминале для каждого символа unicode, который вы пытаетесь вывести.

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

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

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

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

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


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


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