【问题标题】:Convert ICU4C byte to java char将 ICU4C 字节转换为 java char
【发布时间】:2011-07-02 06:09:18
【问题描述】:

我正在通过 JNI 访问一个 ICU4C 函数,该函数返回一个 UChar *(即 unicode 字符数组)......我能够通过将 UChar 数组的每个成员等同于本地 jbyte[] 数组来将其转换为 jbyteArray我创建然后使用 env->SetByteArrayRegion() 函数将其返回给 Java...现在我在 Java 中有 Byte[] 数组,但它几乎都是胡言乱语.. 充其量是奇怪的符号...我不确定问题可能出在哪里......如果这很重要,我正在使用unicode字符......如何在java中正确地将byte []转换为char []?有些东西没有正确映射......这是代码的sn-p:


--- JNI 代码(稍作改动以使其更短)---

static jint testFunction(JNIEnv* env, jclass c, jcharArray srcArray, jbyteArray destArray) {

    jchar* src = env->GetCharArrayElements(srcArray, NULL);
    int n = env->getArrayLength(srcArray);

    UChar *testStr = new UChar[n];
    jbyte destChr[n];

    //calling ICU4C function here    
    icu_function (src, testStr);   //takes source characters and returns UChar*

    for (int i=0; i<n; i++)
        destChr[i] = testStr[i];   //is this correct?

    delete testStr;
    env->SetByteArrayRegion(destArray, 0, n, destChr);
    env->ReleaseCharArrayElements(srcArray, src, JNI_ABORT);

    return (n); //anything for now
}

-- Java 代码-- 字符串 woohoo = "ABCD bal bla bla"; char[] myChars = woohoo.toCharArray();

byte[] myICUBytes = new byte[myChars.length];
int value = MyClass.testFunction (myChars, myICUBytes);

System.out.println(new String(myICUBytes)) ;// produces gibberish & weird symbols

我也尝试过:System.out.println(new String(myICUBytes, Charset.forName("UTF-16"))) 和它一样乱七八糟....

请注意,ICU 函数确实会在 UChar *... 中返回正确的 unicode 字符,介于转换为 jbyteArray 和正在搞砸的 Java 之间...

救命!

【问题讨论】:

  • 请不要重复同样的问题 - 我刚刚花了很多时间回答您的另一个重复问题,今天才发现您的问题已经(显然)解决了。

标签: java unicode java-native-interface icu


【解决方案1】:
destChr[i] = testStr[i];   //is this correct?

这看起来是个问题。

JNI types:

byte   jbyte    signed 8 bits
char   jchar    unsigned 16 bits

ICU4C types:

如果是,则将 UChar 定义为 wchar_t 16 位宽;总是假定为 未签名。

如果 wchar_t 不是 16 位宽,那么 将 UChar 定义为 uint16_t 或 char16_t 因为 GCC >=4.4 可以处理 UTF16 字符串文字。这使得 UChar 平台相关的定义 但允许直接字符串类型 与平台的兼容性 16 位 wchar_t 类型。

因此,除了 icu_function 可能做的任何事情之外,您还试图将 16 位值适合 8 位宽的类型。

如果必须使用 Java 字节数组,我建议通过转码为 Unicode 编码转换为 8 位 char 类型。

套用some C code

UChar *utf16 = (UChar*) malloc(len16 * sizeof(UChar));
//TODO: fill data
// convert to UTF-8
UConverter *encoding = ucnv_open("UTF-8", &status);
int len8 = ucnv_fromUChars(encoding, NULL, 0, utf16, len16, &status);
char *utf8 = (char*) malloc(len8 * sizeof(char));
ucnv_fromUChars(encoding, utf8, len8, utf16, len16, &status);
ucnv_close(encoding);
//TODO: char to jbyte

然后您可以使用 new String(myICUBytes, "UTF-8") 将其转码为 Java 字符串。

我使用 UTF-8 是因为它已经在我的示例代码中,您不必担心字节顺序。根据需要将我的 C 转换为 C++。

【讨论】:

  • 谢谢!!!这就说得通了。我将所有内容都更改为 jcharArray,现在一切正常。 p.s:我没有足够的声誉给你竖起大拇指,但我会尽快:)这里有一个新用户。
【解决方案2】:

您是否考虑过使用 ICU4J?

此外,将字节转换为字符串时,您需要指定字符编码。我对相关库不熟悉,因此无法进一步建议您,但也许这将是“UTF-16”或类似的?

哦,另外值得注意的是,您可能只是收到显示错误,因为您要打印到的终端没有使用正确的字符集和/或没有可用的正确字形。

【讨论】:

  • ICU4J 由于其大小 (5MB+) 而不是一个选项,并且该项目已经具有 ICU4C 和 JNI 集成。但是我确实尝试了 ICu4J,它运行良好,但我正在尝试使用 JNI 和 ICU4C 来实现相同的目标。
  • 关于终端问题,不...我确实考虑到了这一点,因为当我尝试 ICU4J 时它运行良好,所以字形就在那里
猜你喜欢
  • 2017-01-30
  • 1970-01-01
  • 1970-01-01
  • 2018-06-24
  • 1970-01-01
  • 2015-08-23
  • 1970-01-01
  • 2020-01-24
  • 1970-01-01
相关资源
最近更新 更多