2008-09-15 26 views
12

Giả sử rằng ở bên C++, hàm của tôi có một kiểu là jstring có tên là myString. Tôi có thể chuyển đổi nó thành một chuỗi ANSI như sau:Làm cách nào để chuyển đổi jstring thành wchar_t *

const char* ansiString = env->GetStringUTFChars(myString, 0); 

là có một cách để nhận được

const wchar_t* unicodeString = ...

Trả lời

3

Một giải pháp di động và mạnh mẽ là sử dụng iconv, với sự hiểu biết rằng bạn phải biết những gì mã hóa hệ thống của bạn wchar_t sử dụng (UTF-16 trên Windows, UTF-32 trên nhiều hệ thống Unix, ví dụ).

Nếu bạn muốn giảm thiểu sự phụ thuộc vào mã của bên thứ ba, bạn cũng có thể cuộn thủ công công cụ chuyển đổi UTF-8 của riêng mình. Điều này rất dễ dàng nếu chuyển đổi sang UTF-32, hơi khó với UTF-16 vì bạn cũng phải xử lý các cặp thay thế. :-P Ngoài ra, bạn phải cẩn thận để từ chối các hình thức non-shortest hoặc có thể mở các lỗi bảo mật trong một số trường hợp.

+0

Bạn đang đề xuất chuyển đổi chuỗi ký tự thành UTF-8 rồi quay lại UTF-16? Điều đó có thực sự cần thiết không? – Rup

+0

@Rup jstrings đã là UTF-8: "JNI sử dụng các chuỗi UTF-8 được sửa đổi để biểu diễn các loại chuỗi khác nhau. Chuỗi UTF-8 được sửa đổi giống với các chuỗi được sử dụng bởi máy ảo Java. Các chuỗi UTF-8 được sửa đổi được mã hóa sao cho các chuỗi ký tự chỉ chứa các ký tự ASCII không null có thể được biểu diễn chỉ bằng một byte cho mỗi ký tự, nhưng tất cả các ký tự Unicode có thể được biểu diễn ..... Máy ảo Java không nhận dạng được định dạng bốn byte chuẩn UTF-8; sử dụng định dạng hai lần ba byte của chính nó thay thế. " –

+0

@ b1naryatr0phy Thật sao? jni.h trên hệ thống của tôi (cả 1.6 và 1.7) có 'typedef unsigned short jchar;' trông giống như UTF-16 đối với tôi. – Rup

0

Nếu chúng tôi không quan tâm đến khả năng nền tảng chéo, trong cửa sổ, bạn có thể sử dụng chức năng MultiByteToWideChar hoặc các macro hữu ích A2W (ref. example).

3

JNI cũng có chức năng GetStringChars(). Kiểu trả về là const jchar *, jchar là 16-bit trên win32 vì vậy theo cách tương thích với wchar_t. Không chắc đó có phải là UTF-16 thực sự hay cái gì khác ...

+0

Bạn có biết được liệu thứ tự byte của jchar có tương thích với Win32 wchar_t không? Nó nên được, nhưng có lẽ tốt để chắc chắn. :-) –

+0

jchar được đánh máy để unsigned ngắn. Tôi đã không thử nó bản thân mình nhưng đoán của tôi sẽ là "có". –

+0

char == jchar == unsigned 16 bit –

0

Chỉ cần sử dụng env-> GetStringChars (myString, 0); Java pass Unicode bởi bản chất của nó

2

Tôi biết điều này đã được hỏi một năm trước, nhưng tôi không thích các câu trả lời khác vì vậy tôi sẽ trả lời anyway. Dưới đây là cách chúng tôi làm điều đó trong nguồn của chúng tôi:

wchar_t * JavaToWSZ(JNIEnv* env, jstring string) 
{ 
    if (string == NULL) 
     return NULL; 
    int len = env->GetStringLength(string); 
    const jchar* raw = env->GetStringChars(string, NULL); 
    if (raw == NULL) 
     return NULL; 

    wchar_t* wsz = new wchar_t[len+1]; 
    memcpy(wsz, raw, len*2); 
    wsz[len] = 0; 

    env->ReleaseStringChars(string, raw); 

    return wsz; 
} 

EDIT: Giải pháp này hoạt động tốt trên các nền tảng nơi wchar_t là 2 byte, một số nền tảng có một wchar_t 4 byte trong trường hợp giải pháp này sẽ không hoạt động.

+2

Giải pháp này là sai. Tôi đã hút 12 giờ vì điều đó. wchar_t và jchar không cần thiết. Bằng chứng cho điều đó là đầu ra của chương trình thử nghiệm của tôi: '01-26 20: 28: 43.675: E/[LMI-NATIVE] (9280): len: 7, jchar: 2, wchar: 4' – Kobor42

+2

@ Kobor42 - Chương trình thử nghiệm của bạn làm gì? Bạn đang nói rằng bạn tìm thấy một trường hợp nơi wchar_t là 4 byte? Tôi đã không thực sự nhận ra nó, nhưng chức năng này được thiết kế để chạy (chủ yếu) trên Windows, nơi wchar_t luôn luôn 2. Tôi bây giờ nhận ra wchar_t là trình biên dịch cụ thể và có thể khác nhau trên nền tảng của bạn. – Benj

+0

Chính xác. Trên Android trước 2.1 wchar_t là 1 byte. 2.1 và sau là 4 byte. – Kobor42

4

Và ai giải phóng wsz? Tôi muốn giới thiệu STL!

std::wstring JavaToWSZ(JNIEnv* env, jstring string) 
{ 
    std::wstring value; 
    if (string == NULL) { 
     return value; // empty string 
    } 
    const jchar* raw = env->GetStringChars(string, NULL); 
    if (raw != NULL) { 
     jsize len = env->GetStringLength(string); 
     value.assign(raw, len); 
     env->ReleaseStringChars(string, raw); 
    } 
    return value; 
} 
+0

Không phải là một giải pháp tuyệt vời trừ khi sử dụng C++ 11 vì wstring sẽ được trả về theo giá trị. (Rõ ràng đăng C++ 11 nó sẽ được di chuyển xây dựng mà sẽ có hiệu quả) – Benj

+4

value.assign (raw, len); không hợp lệ. Tôi nghĩ rằng nó nên được value.assign (nguyên, thô + len); nhưng tôi chưa thử nghiệm. – mjaggard

+0

Tuyệt vời - làm việc cho tôi một cách hoàn hảo trong C# -> C++/CLI -> JNI -> ứng dụng Java! – bbqchickenrobot

0

Khá đơn giản. Nhưng đừng quên để giải phóng bộ nhớ bằng cách ReleaseStringChars

JNIEXPORT jboolean JNICALL Java_TestClass_test(JNIEnv * env, jobject, jstring string) 
{ 
    const wchar_t * utf16 = (wchar_t *)env->GetStringChars(string, NULL); 
    ... 
    env->ReleaseStringChars(string, utf16); 
} 
13

Nếu điều này giúp ai đó ... Tôi đã sử dụng chức năng này cho một dự án Android:

std::wstring Java_To_WStr(JNIEnv *env, jstring string) 
{ 
    std::wstring value; 

    const jchar *raw = env->GetStringChars(string, 0); 
    jsize len = env->GetStringLength(string); 
    const jchar *temp = raw; 
    while (len > 0) 
    { 
     value += *(temp++); 
     len--; 
    } 
    env->ReleaseStringChars(string, raw); 

    return value; 
} 

Một giải pháp cải tiến có thể là (Cám ơn phản hồi):

std::wstring Java_To_WStr(JNIEnv *env, jstring string) 
{ 
    std::wstring value; 

    const jchar *raw = env->GetStringChars(string, 0); 
    jsize len = env->GetStringLength(string); 

    value.assign(raw, raw + len); 

    env->ReleaseStringChars(string, raw); 

    return value; 
} 
+0

Gọn gàng, mặc dù tôi nghi ngờ việc tải wstring với bộ đệm trong một lần sẽ hiệu quả hơn một ký tự tại một thời điểm. – Rup

+0

Vâng, tôi cũng nghĩ như vậy. Tôi vừa cập nhật câu trả lời của tôi :) – gergonzalez

+0

Trình biên dịch C++ có thông báo rằng bạn đang trả về tự động không và phân bổ nó trên heap chứ không phải ngăn xếp? –

Các vấn đề liên quan