2012-02-28 18 views
10

Tôi đã nhận thấy phương thức chiều dài của std :: string trả về độ dài bằng byte và cùng một phương thức trong std :: u16string trả về số lượng các chuỗi 2 byte.Với C++ 11, tôi vẫn cần thư viện thao tác chuỗi không chuẩn cho văn bản Unicode?

Tôi cũng nhận thấy rằng khi một nhân vật hoặc điểm mã nằm ngoài BMP, chiều dài trả về 4 chứ không phải 2.

Hơn nữa, dãy thoát Unicode được giới hạn \ unnnn, vì vậy bất kỳ điểm mã trên Không thể chèn U + FFFF bằng chuỗi thoát.

Nói cách khác, dường như không có hỗ trợ cho cặp thay thế hoặc điểm mã bên ngoài BMP.

Cho điều này, là thực tiễn được chấp nhận hoặc được khuyến nghị sử dụng thư viện thao tác chuỗi không chuẩn để hiểu UTF-8, UTF-16, cặp thay thế, v.v.

Trình biên dịch của tôi có lỗi hay tôi đang sử dụng các phương pháp thao tác chuỗi chuẩn không chính xác?

Ví dụ:

/* 
* Example with the Unicode code points U+0041, U+4061, U+10196 and U+10197 
*/ 

#include <iostream> 
#include <string> 

int main(int argc, char* argv[]) 
{ 
    std::string example1 = u8"A䁡"; 
    std::u16string example2 = u"A䁡"; 

    std::cout << "Escape Example: " << "\u0041\u4061\u10196\u10197" << "\n"; 
    std::cout << "Example: " << example1 << "\n"; 
    std::cout << "std::string Example length: " << example1.length() << "\n"; 
    std::cout << "std::u16string Example length: " << example2.length() << "\n"; 

    return 0; 
} 

Đây là kết quả tôi nhận được khi biên soạn với GCC 4.7:

Escape Example: A䁡မ6မ7 
Example: A䁡 
std::string Example length: 12 
std::u16string Example length: 6 

Trả lời

6

Lúc nguy cơ đánh giá sớm, có vẻ như với tôi rằng ngôn ngữ được sử dụng trong các tiêu chuẩn trong hơi mơ hồ (mặc dù kết luận cuối cùng là rõ ràng, nhìn thấy ở cuối):

Trong mô tả của literals char16_t (tức là u"..." người như trong ví dụ của bạn), kích thước của một chữ được định nghĩa là:

Kích thước của một chuỗi char16_t đen là tổng số của chuỗi thoát, phổ ký tự-tên, và các nhân vật khác, cộng một cho mỗi ký tự yêu cầu cặp thay thế, cộng một cho ký tự kết thúc u '\ 0'.

Và chú thích thêm làm rõ:

[Lưu ý: Kích thước của một chuỗi char16_t đen là số lượng đơn vị mã, không phải là số lượng ký tự. lưu ý end]

Điều này có nghĩa một định nghĩa của nhân vậtmã đơn vị. Cặp thay thế là một ký tự, nhưng hai đơn vị mã.

Tuy nhiên, các mô tả về phương pháp length() của std::basic_string (trong đó std::u16string có nguồn gốc) tuyên bố:

Trả về số ký tự trong chuỗi, tức là std :: khoảng cách (bắt đầu(), kết thúc ()). Nó giống như size().

Vì nó xuất hiện, mô tả của length() sử dụng từ nhân vật để có nghĩa là những gì định nghĩa của char16_t gọi một đơn vị đang.

Tuy nhiên, kết quả của tất cả điều này là: Độ dài được xác định là đơn vị mã, do đó trình biên dịch của bạn tuân thủ tiêu chuẩn và sẽ có nhu cầu tiếp tục cho các thư viện đặc biệt.

tôi đã sử dụng tài liệu tham khảo dưới đây:

  • Đối với định nghĩa về kích thước của literals char16_t: Here
  • Đối với các mô tả về std::basic_string::length(): Here
+1

Cảm ơn câu trả lời. Tôi cũng quan tâm đến các phương pháp thao tác chuỗi khác như chất nền và cách chúng xử lý UTF-8, UTF-16, cặp thay thế, vv Tôi nên rõ ràng hơn. Tôi đã sử dụng độ dài vì đây là ví dụ dễ nhất để đăng. –

+0

@Ragsdale 30 cal Phải. Tôi cho rằng chúng ta sẽ phải chấp nhận rằng tất cả các phương thức này hoạt động trên các đơn vị mã, không phải là các ký tự, mặc dù các mô tả hơi gây nhầm lẫn. Iterator là một ví dụ tốt. – jogojapan

+0

Vì vậy, nói cách khác, cách tiêu chuẩn duy nhất để làm việc với Unicode là chuyển đổi văn bản thành UTF-32 và sử dụng std :: u32string? Điều đó có vẻ khá lãng phí. –

9

std::basic_string là mã đơn vị theo định hướng, chứ không phải nhân vật theo định hướng. Nếu bạn cần phải đối phó với các điểm mã bạn có thể chuyển đổi sang char32_t, nhưng không có gì trong tiêu chuẩn cho chức năng Unicode nâng cao hơn. Bạn cũng có thể sử dụng trình tự thoát \UNNNNNNNN cho các điểm mã không phải BMP, ngoài việc nhập chúng trực tiếp (giả sử bạn đang sử dụng mã hóa nguồn hỗ trợ chúng).

Tùy thuộc vào nhu cầu của bạn, đây có thể là tất cả hỗ trợ Unicode bạn cần. Rất nhiều phần mềm không cần phải làm nhiều hơn các thao tác cơ bản của chuỗi, chẳng hạn như những thao tác có thể dễ dàng được thực hiện trên các đơn vị mã trực tiếp. Đối với nhu cầu cấp cao hơn một chút, bạn có thể chuyển đổi các đơn vị mã thành các điểm mã và làm việc trên các điểm đó. Đối với các nhu cầu cấp cao hơn, chẳng hạn như làm việc trên các cụm grapheme, cần hỗ trợ bổ sung.

Tôi muốn nói điều này có nghĩa là có hỗ trợ đầy đủ trong tiêu chuẩn để biểu diễn dữ liệu Unicode và thực hiện thao tác cơ bản. Bất kỳ thư viện của bên thứ ba nào được sử dụng cho chức năng cấp cao hơn đều phải xây dựng trên thư viện chuẩn. Theo thời gian, tiêu chuẩn cũng có khả năng làm tăng thêm chức năng cấp cao hơn đó.

0

Vì điều này, là thực hành được chấp nhận hoặc được khuyến nghị sử dụng thư viện thao tác chuỗi không chuẩn để hiểu UTF-8, UTF-16, cặp thay thế, v.v.

Thật khó để nói về thực tiễn được khuyến nghị cho tiêu chuẩn ngôn ngữ được tạo vài tháng trước và chưa được triển khai đầy đủ, nhưng nói chung tôi đồng ý: các tính năng miền địa phương và Unicode trong C++ 11 là vẫn vô vọng (mặc dù chúng rõ ràng là tốt hơn rất nhiều), và đối với công việc nghiêm túc, bạn nên thả chúng và sử dụng ICU hoặc Boost.Locale để thay thế.

Việc bổ sung các chuỗi Unicode và chức năng chuyển đổi vào C++ 11 là bước đầu tiên hướng tới hỗ trợ Unicode thực; thời gian sẽ cho biết liệu chúng có trở nên hữu ích hoặc liệu chúng có bị lãng quên hay không.

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