jni的中文字符串处理

简介:

几个概念首先要明确:

  • java内部是使用16bit的unicode编码(UTF-16)来表示字符串的,无论中文英文都是2字节;
  • jni内部是使用UTF-8编码来表示字符串的,UTF-8是变长编码的unicode,一般ascii字符是1字节,中文是3字节;
  • c/c++使用的是原始数据,ascii就是一个字节了,中文一般是GB2312编码,用两个字节来表示一个汉字。

明确了概念,操作就比较清楚了。下面根据字符流的方向来分别说明一下

1、java --> c/c++

这种情况中,java调用的时候使用的是UTF-16编码的字符串,jvm把这个字符串传给jni,c/c++得到的输入是jstring,这个时候,可以利用jni提供的两种函数,一个是GetStringUTFChars,这个函数将得到一个UTF-8编码的字符串;另一个是GetStringChars这个将得到UTF-16编码的字符串。无论那个函数,得到的字符串如果含有中文,都需要进一步转化成GB2312的编码。

       String        (UTF-16)           | [java]    | --------------------  JNI 调用 [cpp]     |           v        jstring         (UTF-16)           |     +--------+---------+  |GetStringChars    |GetStringUTFChars  |                  |  v                  v wchar_t*           char* (UTF_16)           (UTF-8)

                

2、c/c++ --> java

jni返回给java的字符串,c/c++首先应该负责把这个字符串变成UTF-8或者UTF-16格式,然后通过NewStringUTF或者NewString来把它封装成jstring,返回给java就可以了。

       String        (UTF-16)           ^           | [java]    | --------------------  JNI 返回 [cpp]     |        jstring         (UTF-16)           ^           |     +--------+---------+  ^                  ^  |                  |  |NewString         |NewStringUTF wchar_t*          char* (UTF_16)          (UTF-8)                  

如果字符串中不含中文字符,只是标准的ascii码,那么用GetStringUTFChars/NewStringUTF就可以搞定了,因为这种情况下,UTF-8编码和ascii编码是一致的,不需要转换。

但是如果字符串中有中文字符,那么在c/c++部分进行编码转换就是一个必须了。我们需要两个转换函数,一个是把UTF8/16的编码转成GB2312;一个是把GB2312转成UTF8/16。

这里要说明一下:linux和win32都支持wchar,这个事实上就是宽度为16bit的unicode编码UTF16,所以,如果我们的c/c++程序中完全使用wchar类型,那么理论上是不需要这种转换的。但是实际上,我们不可能完全用wchar来取代char的,所以就目前大多数应用而言,转换仍然是必须的。

具体的转换函数,linux和win32都有一定的支持,比如glibc的mbstowcs就可以用来把GB2312编码转成UTF16,但是这种支持一般是平台相关的(因为c/c++的标准中并没有包括这部分),不全面的(比如glibc就没有提供转成UTF8的编码),不独立的(linux下mbstowcs的行为要受到locale设置的影响)。所以我推荐使用iconv库来完成转换。

iconv库是一个免费的独立的编码转换库,支持很多平台,多种编码(事实上,它几乎可以处理我们所使用的所有字符编码),而且它的行为不受任何外部环境的影响。iconv在*nix平台上,基本上是缺省安装的。在win32平台上需要额外安装。

下面提供一个把GB2312编码的字符串转换成UTF8编码的示例

#include <iconv.h> char* BytesToUtf8(string src, char* dst, int* nout)  {     size_t n_in = src.length();     size_t n_out = *nout;          iconv_t c = iconv_open("UTF-8", "GB2312");     if (c == (iconv_t)-1) {         cerr << strerror(errno) << endl;         return NULL;     }

    char* inbuf = new char [n_in + 1];     if (!inbuf) {         iconv_close(c);         return NULL;     }

    strcpy(inbuf, src.c_str());     memset(dst, 0, n_out);

    char* in = inbuf;     char* out = dst;     if (iconv(c, &in, &n_in, &out, &n_out) == (size_t)-1) {         cerr << strerror(errno) << endl;         out = NULL;     }     else {         n_out = strlen(dst);         out = dst;     }

    iconv_close(c);     *nout = n_out;     delete[] inbuf;

    return out; }

补充几点说明:

1、从jni的接口看,jni提供了UTF16和UTF8两个系列的字符串处理函数,但是由于jni的文档中说,jni的内部实现中是用UTF8作为字符串编码格式的,所以使用UTF8系列比较合适(NewStringUTF/GetStringUTFChars/ReleaseStringUTFChars)

2、使用iconv库的话,运行环境的设置对于编码转换是没有影响的,但是外层java程序对于字符串的解析依赖于运行环境的locale,所以设置正确的locale对于jni意义不大,但是对整个系统还是必要的。


本文转自leonpard 51CTO博客,原文链接:http://blog.51cto.com/leonpard/1172664


相关文章
|
Android开发
Android 如何实现带滚动条的TextView,在更新文字时自动滚动到最后一行
1、主布局代码:       2、主要代码 :   package com.android09; import android.
2583 0
|
6月前
|
人工智能 Linux iOS开发
7.9K star!免费解锁Cursor Pro功能,这个开源神器太强了!
"无需付费即可畅享AI编程神器Cursor的Pro功能,支持Windows/macOS/Linux全平台!"
1904 4
|
10月前
|
设计模式 网络协议 Java
02.单一职责原则详解
单一职责原则(SRP)是面向对象设计的重要原则,强调一个类或模块应仅负责完成一个特定的职责或功能。通过将复杂的功能分解为多个粒度小、功能单一的类,可以提高系统的灵活性、可维护性和可扩展性。本文详细介绍了如何理解单一职责原则,包括方法、接口和类层面的应用,并通过具体例子解释了其优势和判断标准。此外,还探讨了在实际开发中如何平衡类的设计,避免过度拆分导致的复杂性增加。
331 5
|
Kubernetes 调度 数据格式
5分钟搞懂K8S的污点和容忍度(理论+实战)
本文主要快速讲解Kubernetes的污点和容忍度,一句话总结:如果Pod能容忍某个节点上的污点,那么Pod就可以调度到该节点。
5分钟搞懂K8S的污点和容忍度(理论+实战)
成功解决pywintypes.com_error: (-2147221005, '无效的类字符串', None, None)
成功解决pywintypes.com_error: (-2147221005, '无效的类字符串', None, None)
成功解决pywintypes.com_error: (-2147221005, '无效的类字符串', None, None)
|
Ubuntu Linux
ubuntu源码编译指定版本make
以上内容涵盖了在Ubuntu中编译安装指定版本软件的全过程,这是一个技术性很强的操作,不仅可以带来定制化的安装体验,同时也能增加对系统管理和软件构建流程的理解。遵循以上步骤,任何有一定基础的用户都能够按需编译和安装软件。
282 8
|
机器学习/深度学习 人工智能 自然语言处理
【机器学习】python之人工智能应用篇——3D生成技术
在Python中,人工智能(AI)与3D生成技术的结合可以体现在多个方面,比如使用AI算法来优化3D模型的生成、通过机器学习来预测3D模型的属性,或者利用深度学习来生成全新的3D内容。然而,直接通过AI生成完整的3D模型(如从文本描述中生成)仍然是一个活跃的研究领域。 3D生成技术是一种通过计算机程序从二维图像或文本描述自动创建三维模型的过程。这一技术在近年来得到了飞速的发展,不仅为游戏、动画和影视行业带来了革命性的变革,还在虚拟现实、增强现实以及工业设计等多个领域展现出了巨大的应用潜力
305 2
|
机器学习/深度学习 人工智能 弹性计算
|
缓存 监控 NoSQL
Redis经典问题:数据不一致
小米探讨了Redis数据不一致问题及其原因,包括缓存更新失败和rehash异常。提出了解决方案,如重试策略、缩短缓存时间、优化写入策略、监控报警、一致性验证、缓存分层和数据回滚机制。通过这些方法可提升应用的稳定性和性能。
915 2
|
存储 芯片 SoC
ZYNQ程序固化
ZYNQ程序固化