处理unicode ,如何摆脱?安卓/ JAVA

时间:2013-01-25 16:02:36

标签: java android unicode character-encoding

我正在使用终端仿真器库来创建终端,然后我用它将通过串口输入的数据发送到串行设备。可以看到图书馆here

当我向终端输入数据时,正在发送/接收一系列奇怪的字符。我认为unicode替换字符是通过串口发送的,串口设备不知道它是什么并返回〜0。

当我写“test”时终端中显示的内容的屏幕截图:enter image description here

显示发送的字符串和收到的数据的日志。 http://i.imgur.com/x79aPzv.png

我创建了一个EmulatorView,它是终端视图。它提到了钻石here

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中引用to甚至解析它?我不能说是否(!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();
            }

3 个答案:

答案 0 :(得分:1)

Java将文本内部存储为未编码的Unicode。曾经是16位,现在我猜测它是32,因为你在终端上为你想要输出的每个unicode字符获得四个输出字符。

您可能想要做的是使用string.getBytes(“ASCII”)之类的东西将您的unicode字符串转换为直接的单字节ascii。如果终端仿真器处理其他字符集(如Latin-1),请使用它而不是“ASCII”。

然后,将字节传输到终端仿真器而不是字符串。

注意:我不肯定“ASCII”是字符集的确切名称;你会想自己研究一下。另外,我不知道getBytes()会对无法转换为ascii的unicode字符做什么,所以你也想研究它。

ETA:我在您发布的剪贴簿中跟踪代码逻辑时遇到问题。谁调用write(),数据来自哪里,它在哪里?同样的问题适用于sendOverSerial()和onDataReceived()。

无论如何,我几乎已经确定某处,原始的32位Unicode数据被转换为字节而不进行编码。从那时起,无论是按原样发送还是将其重新编码为UTF-8都会产生您所看到的效果。我不知道你发布的任何代码中是怎么发生的,所以我猜它发生在你向我们展示的任何函数被调用之前。

答案 1 :(得分:0)

我已经通过编辑我正在使用的库来解决了这个问题。他们使用的方法是将一个字节转换为一个int,它接受了一个codePoint并对其进行了转换。因此,对于每个按键,使用4个字节。我更改了这个,以便使用一个字节而不是int。没有更多的额外字节。没有什么与编码格式有关。

答案 2 :(得分:0)

您正在使用的库似乎是将代码点作为int(32位)发送,并且您的代码假设其编码为utf-8,它不能正确处理4字节。这与java内部存储文本的方式无关。 Btw Java在内部将文本存储为编码的UTF-16,而不是未编码的unicode。同样,这不是这个问题的原因。这就是您与正在使用的库进行交互的方式。