在JavaJNI中获取真正的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),并且具有相当于

在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时得到的字节序列:

    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,然后将其传递给JNI
NewString()
函数,或2)使用JNI将
char
数据原样复制到Java
byte[]
数组,然后将其传递给
String
构造函数,该构造函数以
byte[]
和字符集名称作为输入,指定“UTF-8”作为字符集。@skboro如果
char*
指向“modified”“UTF-8数据,那么您只需使用JNI
NewStringUTF()
函数本身即可。
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);
}