在JavaJNI中获取真正的UTF-8字符
在JNI代码中,有没有一种简单的方法可以将Java字符串转换为真正的UTF-8字节数组 不幸的是,GetStringUTFChars()几乎完成了所需的功能,但它返回的是一个“修改过的”UTF-8字节序列。主要区别在于修改后的UTF-8不包含任何空字符(因此可以将其视为ANSI C空终止字符串),但另一个区别似乎是Unicode补充字符(如表情符号)的处理方式 诸如U+1F604“张嘴微笑的脸和微笑的眼睛”这样的字符存储为代理项对(两个UTF-16字符U+D83D U+DE04),并且具有相当于F0 9F 98 84的4字节UTF-8,这是在Java中将字符串转换为UTF-8时得到的字节序列:在JavaJNI中获取真正的UTF-8字符,java,encoding,utf-8,java-native-interface,Java,Encoding,Utf 8,Java Native Interface,在JNI代码中,有没有一种简单的方法可以将Java字符串转换为真正的UTF-8字节数组 不幸的是,GetStringUTFChars()几乎完成了所需的功能,但它返回的是一个“修改过的”UTF-8字节序列。主要区别在于修改后的UTF-8不包含任何空字符(因此可以将其视为ANSI C空终止字符串),但另一个区别似乎是Unicode补充字符(如表情符号)的处理方式 诸如U+1F604“张嘴微笑的脸和微笑的眼睛”这样的字符存储为代理项对(两个UTF-16字符U+D83D U+DE04),并且具有相当于
char[] c = Character.toChars(0x1F604);
String s = new String(c);
System.out.println(s);
for (int i=0; i<c.length; ++i)
System.out.println("c["+i+"] = 0x"+Integer.toHexString(c[i]));
byte[] b = s.getBytes("UTF-8");
for (int i=0; i<b.length; ++i)
System.out.println("b["+i+"] = 0x"+Integer.toHexString(b[i] & 0xFF));
char[]c=Character.toChars(0x1F604);
字符串s=新字符串(c);
系统输出打印项次;
对于(int i=0;i,Java文档中对此进行了明确解释:
GetStringUTFChars
const char * GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy);
返回一个指向字节数组的指针,该数组表示修改后的UTF-8编码中的字符串。此数组在由ReleaseStringUTFChars()释放之前有效
JNI使用修改后的UTF-8字符串来表示各种字符串类型。修改后的UTF-8字符串与Java VM使用的字符串相同。修改后的UTF-8字符串经过编码,因此每个字符只能使用一个字节来表示仅包含非空ASCII字符的字符序列,但可以表示所有Unicode字符
\u0001
到\u007F
范围内的所有字符均由单个字节表示,如下所示:
字节中的七位数据给出所表示字符的值
空字符('\u0000'
)和范围'\u0080'
到'\u07FF'
的字符由一对字节x和y表示:
字节表示具有值((x&0x1f)的字符,任何关于如何实现反向转换的指针?转换本机字符*(说“Hello@skboro,假设char*
指向真实的UTF-8数据,而不是“修改的”UTF-8数据,1)手动将UTF-8解码为UTF-16,然后将其传递给JNINewString()
函数,或2)使用JNI将char
数据原样复制到Javabyte[]
数组,然后将其传递给String
构造函数,该构造函数以byte[]
和字符集名称作为输入,指定“UTF-8”作为字符集。@skboro如果char*
指向“modified”“UTF-8数据,那么您只需使用JNINewStringUTF()
函数本身即可。
JNIEXPORT void JNICALL Java_EmojiTest_nativeTest(JNIEnv *env, jclass cls, jstring _s)
{
const jclass stringClass = env->GetObjectClass(_s);
const jmethodID getBytes = env->GetMethodID(stringClass, "getBytes", "(Ljava/lang/String;)[B");
const jstring charsetName = env->NewStringUTF("UTF-8");
const jbyteArray stringJbytes = (jbyteArray) env->CallObjectMethod(_s, getBytes, charsetName);
env->DeleteLocalRef(charsetName);
const jsize length = env->GetArrayLength(stringJbytes);
const jbyte* pBytes = env->GetByteArrayElements(stringJbytes, NULL);
for (int i = 0; i < length; ++i)
fprintf(stderr, "%d: %02x\n", i, pBytes[i]);
env->ReleaseByteArrayElements(stringJbytes, pBytes, JNI_ABORT);
env->DeleteLocalRef(stringJbytes);
}