2010-10-16 95 views
10

Tôi đọc một vài bài về thực hành tốt nhất cho chuỗi và mã hóa ký tự trong C++, nhưng tôi đang đấu tranh một chút với việc tìm cách tiếp cận mục đích chung có vẻ hợp lý và đơn giản. Tôi có thể xin ý kiến ​​về những điều sau đây không? Tôi có khuynh hướng sử dụng UTF-8 và UTF-32, và để xác định cái gì đó như:Mã hóa ký tự và chuỗi ký tự trong C++

typedef std::string string8; 
typedef std::basic_string<uint32_t> string32; 

Lớp string8 sẽ được sử dụng cho UTF-8, và có một kiểu riêng biệt chỉ là một lời nhắc nhở về sự mã hóa . Một thay thế sẽ được cho string8 là một phân lớp của std :: string và để loại bỏ các phương pháp mà không phải là khá đúng cho UTF-8.

Lớp string32 sẽ được sử dụng cho UTF-32 khi kích thước ký tự cố định được mong muốn.

Hàm CPP UTF-8, utf8 :: utf8to32() và utf8 :: utf32to8() hoặc thậm chí các hàm bao bọc đơn giản hơn, sẽ được sử dụng để chuyển đổi giữa hai hàm.

+0

Lưu ý rằng 'string8' vẫn là cùng loại với' std :: string'; nó chỉ có một cái tên khác. –

+0

Các hàm 'std :: basic_string' * nào * phù hợp với UTF-8? – dalle

+0

UTF-32 mua bạn trên wstring/Unicode là gì? btw Visual Studio định nghĩa 'u16string' và' u32string'. –

Trả lời

9

Nếu bạn có kế hoạch chỉ đi dây xung quanh và không bao giờ kiểm tra chúng, bạn có thể sử dụng đồng bằng std::string mặc dù đó là một công việc người đàn ông nghèo.

Vấn đề là hầu hết các khuôn khổ, thậm chí tiêu chuẩn, có mã hóa được thực thi ngu ngốc (tôi nghĩ) trong bộ nhớ. Tôi nói ngu ngốc bởi vì mã hóa chỉ nên quan trọng trên giao diện, và những mã hóa không thích nghi cho thao tác trong bộ nhớ của dữ liệu.

Hơn nữa, mã hóa dễ dàng (đó là chuyển đổi đơn giản CodePoint -> byte và ngược lại) trong khi khó khăn chính là thực sự thao tác dữ liệu.

Với 8 bit hoặc 16 bit, bạn có nguy cơ cắt một ký tự ở giữa vì không phải std::string cũng không phải std::wstring là nhận thức được ký tự Unicode là gì. Tệ hơn nữa, ngay cả với mã hóa 32 bit, có nguy cơ tách một ký tự khỏi dấu phụ áp dụng cho nó, điều này cũng ngu ngốc.

Việc hỗ trợ Unicode trong C++ do đó cực kỳ nhỏ, theo như tiêu chuẩn có liên quan.

Nếu bạn thực sự muốn thao tác chuỗi Unicode, bạn cần một thùng chứa nhận thức Unicode. Cách thông thường là sử dụng thư viện , mặc dù giao diện của nó thực sự là C-ish. Tuy nhiên bạn sẽ nhận được mọi thứ bạn cần để thực sự làm việc trong Unicode với nhiều ngôn ngữ.

+1

Tôi tìm thấy bình luận của bạn về dấu phụ một chút đáng sợ. Đó là một ý nghĩa phù hợp nhất với những gì tôi đang cố gắng làm, đó là để xử lý các chuỗi "chính xác" một cách tương đối đơn giản. – nassar

+0

@nassar: thật không may là nó đáng sợ vì chúng tôi thiếu sự hỗ trợ thích hợp: '( –

+0

ICU có (trong số các giao diện khác trong C++) một lớp chuỗi C++ tương tác với std :: string –

1

Cách tiếp cận đặc điểm được mô tả here có thể hữu ích. Đó là một kỹ thuật cũ nhưng hữu ích.

1

Không chỉ định mã hóa ký tự nào phải được sử dụng cho chuỗi, chuỗi v.v. Cách thông thường là sử dụng unicode trong chuỗi rộng. Loại và mã hóa nào nên được sử dụng tùy thuộc vào yêu cầu của bạn.

Nếu bạn chỉ cần chuyển dữ liệu từ A đến B, hãy chọn std :: string with UTF-8 encoding (không giới thiệu loại mới, chỉ cần sử dụng std :: string). Nếu bạn phải làm việc với các chuỗi (trích xuất, concat, sắp xếp, ...), hãy chọn std :: wstring và dưới dạng mã hóa UCS2/UTF-16 (chỉ BMP) trên Windows và UCS4/UTF-32 trên Linux. Lợi ích là kích thước cố định: mỗi ký tự có kích thước 2 (hoặc 4 cho UCS4) byte trong khi std :: string với UTF-8 trả về kết quả sai().

Để chuyển đổi, bạn có thể kiểm tra sizeof (std :: wstring :: value_type) == 2 hoặc 4 để chọn UCS2 hoặc UCS4. Tôi đang sử dụng thư viện ICU, nhưng có thể có libs wrapper đơn giản.

Bắt nguồn từ std :: string không được khuyến khích vì basic_string không được thiết kế cho (thiếu thành viên ảo v.v.). Nếu bạn thực sự thực sự thực sự cần loại của riêng bạn như std :: basic_string < my_char_type> viết một chuyên môn tùy chỉnh cho việc này.

Chuẩn C++ 0x mới định nghĩa wstring_convert <> và wbuffer_convert <> để chuyển đổi với tiêu chuẩn :: codecvt từ bộ ký tự hẹp thành bộ ký tự rộng (ví dụ: UTF-8 thành UCS2). Visual Studio 2010 đã triển khai thực hiện điều này, ngay lập tức.

+2

Tôi đã cố ý tránh UCS-2, bởi vì dường như tôi đang gặp rắc rối khi xử lý mã hóa ký tự, người ta cũng có thể làm đúng và hỗ trợ đầy đủ Unicode. (Đồng thời, tôi đang tìm kiếm một cái gì đó ít cồng kềnh hơn ICU cho mục đích sử dụng chung.) Đối với UTF-16, nó dường như có những nhược điểm của cả hai mã hóa độ dài biến và sử dụng rất nhiều bộ nhớ. Đó là lý do tại sao tôi đề xuất sử dụng UTF-8 và UTF-32 kết hợp. – nassar

+0

Điểm lấy về bắt nguồn từ std :: string. Cảm ơn! – nassar

+1

Tôi nghĩ việc định nghĩa một kiểu mới không quan trọng, nhưng nhiều người thấy std :: string in code sẽ có xu hướng quên đi các ký tự nhiều byte và sử dụng sai vị trí ký tự. Thực tế là UTF-8 có thể được chuyển tải trong các bình luận, nhưng có một lời nhắc trong tên kiểu có vẻ hữu ích bởi vì các phương thức như std :: string :: insert() gợi ý các ký tự 8 bit theo ý kiến ​​của tôi. – nassar

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