2009-01-12 29 views
9

Nhìn vào unicode standard, họ khuyên bạn nên sử dụng đồng bằng char s để lưu trữ chuỗi được mã hóa UTF-8. Điều này làm việc như mong đợi với C + + và cơ bản std::string, hoặc làm trường hợp tồn tại, trong đó mã hóa UTF-8 có thể tạo ra vấn đề?Cách tốt nhất để lưu trữ chuỗi UTF-8 trong bộ nhớ trong C/C++ là gì?

Ví dụ: khi tính toán độ dài, nó có thể không giống với số byte - cách xử lý này phải được xử lý như thế nào? Đọc tiêu chuẩn, tôi có thể sử dụng mảng char để lưu trữ, nhưng tôi vẫn sẽ cần phải viết các hàm như strlen v.v. của riêng tôi, hoạt động trên văn bản được mã hóa, vì tôi hiểu được vấn đề, tiêu chuẩn các thường trình chỉ là ASCII, hoặc mong đợi các chữ số rộng (16 bit trở lên), không được tiêu chuẩn unicode đề xuất. Cho đến nay, nguồn tốt nhất mà tôi tìm thấy về những thứ mã hóa là một bài đăng trên Joel's on Software, nhưng nó không giải thích những gì chúng tôi nghèo C++ phát triển nên sử dụng :)

Trả lời

5

Có thư viện có tên "UTF8-CPP", cho phép bạn lưu trữ chuỗi UTF-8 của mình trong tiêu chuẩn std :: string objects và cung cấp các hàm bổ sung để liệt kê và thao tác các ký tự utf-8.

Tôi chưa thử nghiệm nó, vì vậy tôi không biết nó có giá trị gì, nhưng tôi đang xem xét sử dụng nó bản thân mình.

+0

Đây có lẽ là cách để đi. Ngoài ra còn có thư viện ICU, mà nhiều hơn hoặc ít hơn cùng một điều. – sastanin

0

Từ UTF-8 and Unicode FAQ: C support for Unicode:

#include <stdio.h> 
#include <locale.h> 

int main() 
{ 
    if (!setlocale(LC_CTYPE, "")) { 
    fprintf(stderr, "Can't set the specified locale! " 
      "Check LANG, LC_CTYPE, LC_ALL.\n"); 
    return 1; 
    } 
    printf("%ls\n", L"Schöne Grüße"); 
    return 0; 
} 

Cũng từ here:

Tin tốt lành là nếu bạn sử dụng wchar_t* chuỗi và gia đình của chức năng liên quan đến họ như wprintf, wcslenwcslcat, bạn đang xử lý các giá trị Unicode. Trong thế giới C++, bạn có thể sử dụng std::wstring để cung cấp giao diện thân thiện. Đơn khiếu nại duy nhất của tôi là đây là các ký tự 32 bit (4 byte), vì vậy chúng là bộ nhớ con heo cho tất cả các ngôn ngữ. Lý do cho lựa chọn này là đảm bảo rằng mỗi ký tự có thể được thể hiện có thể được biểu diễn bởi một giá trị.

PS. Đây có lẽ là đặc trưng cho Linux. Có một thư viện ICU để xử lý những thứ phức tạp.

+0

Điều này không hoạt động ngay khi tôi thử trên OS X với GCC 4.01: Nó in các ký tự không phải ASCII dưới dạng ký tự thoát trong mã bát phân. Khi tôi viết printf ("% s \ n", "Schöne Grüße"); thay vào đó, nó in chính xác. Do đó, đây không phải là giải pháp để nhận được số ký tự utf-8 trong một chuỗi. –

+0

Tôi không thể nói cho OS X, nhưng ví dụ này chắc chắn làm việc với GCC 4.3.2 trên GNU/Linux, * bằng ngôn ngữ UTF-8 *. Ngôn ngữ của bạn trong OS X là gì? Tôi nghi ngờ nó không phải là một miền địa phương Unicode. Ngoài ra, có thể, các ngôn ngữ được xử lý khác nhau trong OS X, tôi không biết. – sastanin

+1

Sai trên rất nhiều cấp độ, tôi sợ. Ký tự bên ngoài bộ ký tự được bảo đảm; giả sử giao diện điều khiển có thể in wchar_t's. wchar_t là 2 byte trên hầu hết các máy tính, – MSalters

1

Những gì chúng tôi đã giải quyết bằng: lưu trữ UTF8 trong chuỗi std ::. Bạn có thể thực hiện hầu hết các hoạt động ngay bây giờ, ngoại trừ những thứ như tính toán độ dài. Sử dụng hàm UTF8-> std :: wstring conversion (boost :: from_utf8 chẳng hạn) để chuyển đổi thành std :: wstring khi bạn cần các thao tác như vậy.

2

Phụ thuộc vào những gì bạn muốn làm với Chuỗi UTF8. Nếu tất cả những gì bạn quan tâm là đọc vào và ra các chuỗi UTF8 thì tất cả đều hoạt động miễn là bạn đã đặt đúng ngôn ngữ. Chúng tôi đã làm điều này một thời gian. Chúng tôi có một số quá trình máy chủ không làm gì với chuỗi như vậy. Có chuỗi được thiết lập bởi người dùng trong Java và đến như là UTF8 và chúng tôi xử lý chúng trong bộ đệm str tiêu chuẩn c. Sau đó chúng tôi gửi dữ liệu trở lại Java để chuyển đổi nó trở lại.

Nếu bạn muốn độ dài bằng ký tự UTF8 thì bạn muốn các hàm có thể xử lý bản dịch cho bạn.

Nhưng bạn có thể cuộn của riêng bạn ví dụ utf8-strlen

2

strlen đếm số ký tự null trước khi là người đầu tiên \ 0. Trong UTF-8, số đó là số sane (số byte được sử dụng), nhưng số đếm không phải là số ký tự (một ký tự UTF-8 thường là 1-4 ký tự). basic_string không lưu trữ \ 0, nhưng nó cũng giữ một số byte.

strcpy hoặc ctor bản sao basic_string sao chép tất cả các byte mà không cần nhìn quá gần.

Tìm chuỗi con hoạt động OK, vì cách mã hóa UTF_8. Các giá trị được phép cho byte đầu tiên của một ký tự khác với byte thứ hai đến thứ 4 (trước đây không bao giờ bắt đầu bằng 10xxxxxx, sau này luôn luôn)

Lấy chuỗi con là khó - làm thế nào để bạn xác định vị trí? Nếu bắt đầu và kết thúc được tìm thấy bằng cách tìm kiếm các dấu văn bản ASCII (ví dụ: [và]) thì không có vấn đề gì. Bạn sẽ chỉ nhận được các byte ở giữa, đó là một chuỗi UTF8 hợp lệ quá. Bạn không thể quấy rối vị trí, hoặc thậm chí bù đắp tương đối mặc dù. Ngay cả một tương đối bù đắp của 1 nhân vật có thể được khó khăn; có bao nhiêu byte? Bạn sẽ kết thúc viết một hàm như SkipOneChar.

3

Một ví dụ với ICU library (C, C++, Java):

#include <iostream> 
#include <unicode/unistr.h> // using ICU library 

int main(int argc, char *argv[]) { 
    // constructing a Unicode string 
    UnicodeString ustr1("Привет"); // using platform's default codepage 
    // calculating the length in characters, should be 6 
    int ulen1=ustr1.length(); 
    // extracting encoded characters from a string 
    int const bufsize=25; 
    char encoded[bufsize]; 
    ustr1.extract(0,ulen1,encoded,bufsize,"UTF-8"); // forced UTF-8 encoding 
    // printing the result 
    std::cout << "Length of " << encoded << " is " << ulen1 << "\n"; 
    return 0; 
} 

xây dựng như

$ g++ -licuuc -o icu-example{,.cc} 

chạy

$ ./icu-example 
Length of Привет is 6 

trình cho tôi trên Linux với GCC 4.3.2 và libicu 3.8.1. Xin lưu ý rằng nó in bằng UTF-8 cho dù ngôn ngữ hệ thống là gì. Bạn sẽ không nhìn thấy nó một cách chính xác nếu bạn không phải là UTF-8.

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