3

我必须将一些聊天代码从 iOS 移植到 Android。在将聊天消息发送到套接字之前,iOS 代码使用NSNonLossyASCIIStringEncoding该类作为 NSString::dataUsingEncoding 的参数。

你会如何在Android中做到这一点?关于相反解码的相同问题。

例如,如果不这样做,换行符会在另一台手机上收到的消息中消失。

iOS上的代码:

NSData *data1 = [myStringTosend dataUsingEncoding:NSNonLossyASCIIStringEncoding];
NSString *goodValue = [[[NSString alloc] initWithData:data1 encoding:NSUTF8StringEncoding] autorelease];

和解码:

NSData *data = [[NSData alloc] initWithData:[response dataUsingEncoding:NSASCIIStringEncoding]];

到目前为止(并且不正确),Android 端的编码:

OutputStream os = socket.getOutputStream();
os.write(request.getBytes("UTF-8"));
os.flush();

和解码:

while ((bytesRead = is.read(buffer, 0, BUFFER_SIZE)) >= 0) {
    if (bytesRead > 0) response.append(new String(buffer, 0, bytesRead, "UTF-8"));
    if (bytesRead < BUFFER_SIZE) break;
}
4

3 回答 3

9

@portforwardpodcast 是绝对正确的,如果可能的话,您应该避免对您的 utf8 进行 ASCII 编码,而是将您的堆栈设置为直接处理/存储 utf8。也就是说,如果您无法更改行为,以下代码可能会有所帮助。

虽然没有公布如何NSNonLossyASCIIStringEncoding工作的解释,但根据其输出,它看起来像:

  • 扩展 ASCII 范围内的字节(十进制值 128 - 255)使用八进制编码进行转义(例如ñ,十进制值 241 -> \361
  • 使用十六进制编码将非 ASCII 代码点转义为两个字节块(例如,它占用 32 位,十进制值 128549 -> \ud83d\ude25

所以要编码:

public static String encodeToNonLossyAscii(String original) {
    Charset asciiCharset = Charset.forName("US-ASCII");
    if (asciiCharset.newEncoder().canEncode(original)) {
        return original;
    }
    StringBuffer stringBuffer = new StringBuffer();
    for (int i = 0; i < original.length(); i++) {
        char c = original.charAt(i);
        if (c < 128) {
            stringBuffer.append(c);
        } else if (c < 256) {
            String octal = Integer.toOctalString(c);
            stringBuffer.append("\\");
            stringBuffer.append(octal);
        } else {
            String hex = Integer.toHexString(c);
            stringBuffer.append("\\u");
            stringBuffer.append(hex);
        }
    }
    return stringBuffer.toString();
}

并进行解码(这可以通过在锁定步骤中解析两种类型的编码来提高效率,而不是作为两个单独的传递):

private static final Pattern UNICODE_HEX_PATTERN = Pattern.compile("\\\\u([0-9A-Fa-f]{4})");
private static final Pattern UNICODE_OCT_PATTERN = Pattern.compile("\\\\([0-7]{3})");

public static String decodeFromNonLossyAscii(String original) {
    Matcher matcher = UNICODE_HEX_PATTERN.matcher(original);
    StringBuffer charBuffer = new StringBuffer(original.length());
    while (matcher.find()) {
        String match = matcher.group(1);
        char unicodeChar = (char) Integer.parseInt(match, 16);
        matcher.appendReplacement(charBuffer, Character.toString(unicodeChar));
    }
    matcher.appendTail(charBuffer);
    String parsedUnicode = charBuffer.toString();

    matcher = UNICODE_OCT_PATTERN.matcher(parsedUnicode);
    charBuffer = new StringBuffer(parsedUnicode.length());
    while (matcher.find()) {
        String match = matcher.group(1);
        char unicodeChar = (char) Integer.parseInt(match, 8);
        matcher.appendReplacement(charBuffer, Character.toString(unicodeChar));
    }
    matcher.appendTail(charBuffer);
    return charBuffer.toString();
}
于 2015-12-22T21:14:00.750 回答
2

不要使用 NSNonLossyASCIIStringEncoding,使用 utf-8 编码。我刚刚在 ios+android+java spring backend 上自己解决了这个问题,我花了大约 4 天的时间来解决所有问题。Android 无法显示表情符号,但这为我提供了几乎所有(或所有不确定)语言的完整字符支持。以下是对我有帮助的文章:

必读: http: //blog.manbolo.com/2012/10/29/supporting-new-emojis-on-ios-6 http://blog.manbolo.com/2011/12/12/supporting-ios- 5-新表情符号编码

查看数据库中字符串的十六进制字节:如何查看存储在 MySQL 列中的原始字节?

有关如何设置 MySQL 的详细信息:http: //technovergence-en.blogspot.com/2012/03/mysql-from-utf8-to-utf8mb4.html

utf8 深入常见问题解答- http://www.unicode.org/faq/utf_bom.html#utf8-4

有关符号差异的详细信息:\ud83d\udc7d 和内存中的十六进制值:0xF09F91BD http://en.wikipedia.org/wiki/UTF-8#Description

使用它来复制和粘贴字符以查看真正的十六进制字节值(适用于表情符号):http://perishablepress.com/tools/utf8-hex/index.php

获取 Spring 以在 url 中支持 utf8(用于 GET 参数)http://forum.springsource.org/showthread.php?93728-RequestParam-doesn-t-seem-to-be-decoded 获取参数编码 http://forum。 springsource.org/showthread.php?112181-Unable-to-Override-the-Spring-MVC-URL-decoding-which-uses-default-quot-ISO-8859-1-quot

于 2013-01-19T05:07:14.757 回答
2

我的答案代码相当于 IOS NSNonLossyASCIIStringEncoding for Android。

在你的 gradle 中放在 depandancy 下面。

 compile 'org.apache.commons:commons-lang3:3.4'

然后像这样把方法放到你的 Utils 类中

 public static String encode(String s)
{
    return StringEscapeUtils.escapeJava(s);

}

public static String decode(String s)
{
    return StringEscapeUtils.unescapeJava(s);

}

然后只需在要编码字符串或像这样解码字符串的地方调用此方法

//for encode
String stencode = Utils.encode("mystring");


//for decode
String stdecode = Utils.decode("mystring")
于 2017-03-17T08:20:17.847 回答