Преобразовать байт ICU4C в java char

Я получаю доступ к функции ICU4C через JNI, которая возвращает UChar * (т.е. массив символов Unicode).... Я смог преобразовать это в jbyteArray, приравняв каждый элемент массива UChar к локальному массиву jbyte[], который я создал и затем я вернул его на Java с помощью функции env->SetByteArrayRegion()... теперь у меня есть массив Byte[] в Java, но все это в значительной степени тарабарщина. В лучшем случае странные символы... Я не уверен, в чем проблема может быть... Я работаю с символами Юникода, если это имеет значение... как правильно преобразовать byte[] в char[] в java? Что-то не отображается правильно... Вот фрагмент кода:


--- Код 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 -- string wohoo = "ABCD bal bla bla"; char[] myChars = wohoo.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 *... где-то между преобразованием в jbyteArray и Java, что испортилось...

Помощь!


person Ayyoudy    schedule 22.02.2011    source источник
comment
Пожалуйста, не задавайте один и тот же вопрос дважды - я только что потратил много времени, отвечая на ваш другой дубликат, только чтобы сегодня узнать, что ваша проблема уже (очевидно) решена.   -  person Lawrence Dol    schedule 24.02.2011


Ответы (2)


destChr[i] = testStr[i];   //is this correct?

Это похоже на проблему.

типы JNI:

byte   jbyte    signed 8 bits
char   jchar    unsigned 16 bits

типы ICU4C:

Определите 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, я предлагаю преобразовать его в 8-битный тип char путем перекодирования в кодировку Unicode.

Перефразируя некоторый код C :

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

Затем вы можете перекодировать это в строку Java, используя new String(myICUBytes, "UTF-8").

Я использовал кодировку UTF-8, потому что она уже была в моем примере кода, и вам не нужно беспокоиться о порядке следования байтов. Преобразуйте мой C в C++ соответствующим образом.

person McDowell    schedule 22.02.2011
comment
Спасибо!!! В этом есть смысл. Я изменил все на jcharArray, и теперь все работает. p.s. У меня недостаточно репутации, чтобы поставить вам большой палец вверх, но я сделаю это, как только у меня будет достаточно :) Здесь новый пользователь. - person Ayyoudy; 23.02.2011

Рассматривали ли вы возможность использования ICU4J?

Кроме того, при преобразовании ваших байтов в строку вам нужно будет указать кодировку символов. Я не знаком с обсуждаемой библиотекой, поэтому ничего не могу посоветовать, но, возможно, это будет "UTF-16" или что-то подобное?

О, и также стоит отметить, что вы можете просто получать ошибки отображения, потому что терминал, на который вы печатаете, не использует правильный набор символов и / или не имеет нужных доступных глифов.

person dty    schedule 22.02.2011
comment
ICU4J не подходит из-за его размера (5 МБ+), и в проекте уже есть ICU4C и целочисленность JNI. Однако я попробовал ICu4J, и он работал хорошо, но я пытаюсь добиться того же, используя JNI и ICU4C. - person Ayyoudy; 22.02.2011
comment
Что касается проблемы с терминалом, нет ... Я принял это во внимание, поскольку он хорошо работает, когда я пробовал ICU4J, поэтому глифы есть - person Ayyoudy; 22.02.2011