2010-10-30 23 views
18

Bạn sẽ nghĩ rằng điều này có sẵn, nhưng tôi đang gặp khó khăn khi tìm một hàm thư viện đơn giản sẽ chuyển đổi chuỗi C hoặc C++ từ ISO -8859-1 mã hóa thành UTF-8. Tôi đang đọc dữ liệu trong mã hóa 8-bit ISO-8859-1, nhưng cần phải chuyển đổi nó thành chuỗi UTF-8 để sử dụng trong cơ sở dữ liệu SQLite và cuối cùng là một ứng dụng Android.Chuyển đổi chuỗi ISO-8859-1 sang UTF-8 trong C/C++

Tôi đã tìm thấy một sản phẩm thương mại nhưng vượt quá ngân sách của tôi tại thời điểm này.

+3

Có không có gì đơn giản về nó. Bạn có thể sử dụng thư viện ICU nguồn mở. –

+3

Nếu bạn phải làm điều đó, thì mã đơn giản nhất là tạo trước một bảng gồm 128 ký tự UTF-8 tương ứng với các ký tự 8859-1 với bộ bit trên cùng. 128 8859-1 ký tự khác chưa được sửa đổi. Bằng cách đó, mã của bạn không phải hiểu Unicode chút nào. Ngoài ra, hãy cẩn thận sự khác biệt giữa ISO-8859-1 và Windows CP-1252. Sau này có một số ký tự phụ trong đó 8859-1 có khoảng trống (các điểm mã không sử dụng).Trừ khi bạn có nghĩa vụ phải xác nhận rằng đầu vào của bạn thực sự là ISO-8859-1, không có điểm nào không chấp nhận CP-1252, bởi vì bạn * sẽ * thấy nó bị sai lệch. –

+0

@Steve: vì UTF-8 có độ dài thay đổi (trong trường hợp này, 1 hoặc 2 byte cho mỗi ký tự), bảng tra cứu không dễ sử dụng. Xem câu trả lời của tôi nên nhanh và đơn giản hơn rất nhiều. –

Trả lời

31

Nếu mã hóa nguồn của bạn sẽ luôn được ISO-8859-1, đây là tầm thường. Đây là vòng lặp:

unsigned char *in, *out; 
while (*in) 
    if (*in<128) *out++=*in++; 
    else *out++=0xc2+(*in>0xbf), *out++=(*in++&0x3f)+0x80; 

Vì lý do an toàn, bạn cần đảm bảo bộ đệm đầu ra lớn gấp hai lần bộ đệm đầu vào hoặc giới hạn kích thước khác và kiểm tra trong điều kiện vòng lặp.

+1

Rất tiếc. Điều này rất hữu ích! Tôi không mong chờ một thuật toán tra cứu bảng nào khác. Bây giờ cho ANSEL-to-UTF-8 ... – gordonwd

+8

Điều này chắc chắn trả lời câu hỏi. Nhưng như tôi đã nói trong một bình luận ở trên, mọi người * sẽ * gửi cho bạn CP-1252 sai lệch như ISO-8859-1. Các máy chủ web là ví dụ mà tôi đã vấp phải điều đó đã thuyết phục tôi về vấn đề này, nhưng cũng có các trình soạn thảo văn bản tuyên bố tiết kiệm là "Latin-1" khi chúng không. Điều đó "nếu mã hóa nguồn của bạn sẽ luôn là ISO-8859-1" là một "khá lớn" nếu "và có thể khó theo dõi và loại bỏ trách nhiệm sai trái. –

+0

@Steve: Bạn có thể thêm lỗi goto 'else if (* in <192);' trường hợp bị lỗi khi gặp phải bất kỳ mã kiểm soát ISO-8859-1 nào (có thể là các ký tự Windows-1252 bị lỗi và không phải là ký tự hữu ích dù sao). –

3

Chuẩn C++ 03 không cung cấp chức năng chuyển đổi trực tiếp giữa các bộ ký tự cụ thể.

Tùy thuộc vào hệ điều hành của bạn, bạn có thể sử dụng iconv() trên Linux, MultiByteToWideChar() & Co. trên Windows. Một thư viện cung cấp hỗ trợ lớn cho chuyển đổi chuỗi là thư viện ICU là nguồn mở.

+0

> ** ”** Tiêu chuẩn C++ không cung cấp chức năng chuyển đổi trực tiếp giữa các bộ ký tự –

0

ISO-8859-1 đến UTF-8 không liên quan gì hơn thuật toán mã hóa vì ISO-8859-1 là tập hợp con của Unicode. Vì vậy, bạn đã có các điểm mã Unicode. Kiểm tra Wikipedia cho thuật toán.

Các khía cạnh C++ - tích hợp với iostreams - khó hơn nhiều.

Tôi đề nghị bạn đi bộ xung quanh ngọn núi đó thay vì cố gắng khoan qua nó hoặc leo lên nó, nghĩa là, thực hiện một chuỗi đơn giản để chuyển đổi chuỗi.

Cheers & h.,

+0

Thuật toán không hoàn toàn nhỏ, đặc biệt khi người mới sử dụng các trình lập trình C trung gian thường sử dụng nhầm lẫn' char * 'trong đó' unsigned char * 'là cần thiết. Các đặc tính quan trọng hơn trong định nghĩa UTF-8, đặc biệt là bạn cần loại bỏ các điểm mã hóa thay thế và các giá trị ngoài phạm vi. Rất may, những thứ đó sẽ không xuất hiện trong bộ mã hóa chỉ cần xử lý đầu vào ISO-8859-1, nhưng nếu bạn viết bộ mã hóa giới hạn như vậy thì có khả năng ai đó sẽ lạm dụng nó cho một phạm vi nhập liệu lớn hơn mà không cần thêm bất kỳ séc nào. –

+0

@ MichałLeon: Unicode không phải là mã hóa. Có một số mã hóa Unicode khác nhau, bao gồm UTF-8 và UTF-16. 256 điểm mã đầu tiên của Unicode giống với Latin 1 (a.k.a. ISO-8859-1). Lưu ý: nhấn mạnh không làm cho bạn ít hơn ở tỷ lệ cược với thực tế tầm thường. Lần tới, thay vì la hét và lật đổ, hãy xem xét chỉ đơn giản là kiểm tra sự thật, hoặc chỉ hỏi về bất cứ điều gì bạn không hiểu. –

+0

@Martin: Khối mã Unicode từ 128 đến 255 được gọi là ["bổ sung Latin-1" của Unicode] (https://en.wikipedia.org/wiki/Latin-1_Supplement_ (Unicode_block)), bởi vì nó là giống như Latin-1. Unicode là phần mở rộng trực tiếp của Latin-1. Bạn nhận xét là vô lý vô nghĩa, loại kỹ thuật-babble có thể ảnh hưởng đến người phi kỹ thuật và cho biết trolling. Tôi đoán bạn đang trolling. –

2

Các folks Unicode có một số bảng có thể hữu ích nếu phải đối mặt với Windows 1252 thay vì đúng ISO-8859-1. Con số cuối cùng có vẻ là this one ánh xạ mọi điểm mã trong CP1252 đến một điểm mã trong Unicode. Mã hóa Unicode dưới dạng UTF-8 là một bài tập đơn giản.

Sẽ không khó để phân tích trực tiếp bảng đó và tạo bảng tra cứu từ bảng đó tại thời gian biên dịch.

7

Để C++ i sử dụng này:

std::string iso_8859_1_to_utf8(std::string &str) 
{ 
    string strOut; 
    for (std::string::iterator it = str.begin(); it != str.end(); ++it) 
    { 
     uint8_t ch = *it; 
     if (ch < 0x80) { 
      strOut.push_back(ch); 
     } 
     else { 
      strOut.push_back(0xc0 | ch >> 6); 
      strOut.push_back(0x80 | (ch & 0x3f)); 
     } 
    } 
    return strOut; 
} 
Các vấn đề liên quan