2011-01-05 43 views
9

Tôi phải đi qua một số văn bản và viết đầu ra UTF8 theo các mẫu ký tự. Tôi nghĩ rằng nó sẽ được dễ dàng nếu tôi có thể làm việc với các điểm mã và làm cho nó chuyển đổi sang UTF8. Tôi đã được đọc về unicode và UTF8 nhưng không thể tìm thấy một giải pháp tốt. Bất kỳ trợ giúp sẽ được đánh giá cao.Thư viện C để chuyển đổi các điểm mã unicode thành UTF8?

Trả lời

33

Chuyển đổi các điểm mã Unicode sang UTF-8 là rất tầm thường mà làm cho cuộc gọi đến một thư viện có thể mất nhiều mã hơn là chỉ làm điều đó cho mình:

if (c<0x80) *b++=c; 
else if (c<0x800) *b++=192+c/64, *b++=128+c%64; 
else if (c-0xd800u<0x800) goto error; 
else if (c<0x10000) *b++=224+c/4096, *b++=128+c/64%64, *b++=128+c%64; 
else if (c<0x110000) *b++=240+c/262144, *b++=128+c/4096%64, *b++=128+c/64%64, *b++=128+c%64; 
else goto error; 

Ngoài ra, làm việc đó mình có nghĩa là bạn có thể điều chỉnh các api để loại w ork bạn cần (nhân vật-tại-một-thời gian? Hoặc chuỗi dài?) Bạn có thể xóa các trường hợp lỗi nếu bạn biết đầu vào của mình là giá trị vô hướng Unicode hợp lệ.

Hướng khác là khó hơn một chút để có được chính xác. Tôi khuyên bạn nên sử dụng phương pháp automaton hữu hạn thay vì các vòng bit số học thông thường đôi khi giải mã các chuỗi không hợp lệ làm bí danh cho các ký tự thực (rất nguy hiểm và có thể dẫn đến các vấn đề bảo mật).

Chỉnh sửa: Ngay cả khi bạn kết thúc bằng thư viện, tôi nghĩ bạn nên tự mình viết thử trước hoặc ít nhất nghiên cứu nghiêm túc đặc tả UTF-8 trước khi tiếp tục. Rất nhiều thiết kế xấu có thể đến từ việc xử lý UTF-8 như một hộp đen khi toàn bộ vấn đề là nó không phải là hộp đen nhưng được tạo ra để có các thuộc tính rất mạnh và quá nhiều lập trình viên mới cho UTF-8 không thấy điều này cho đến họ đã làm việc với nó rất nhiều.

+6

@Philipp: Viết nhiều mã hơn để bọc một thư viện để phù hợp với nhu cầu giao diện của bạn và làm việc xung quanh các lỗi của nó tốt hơn? Nếu bạn quan tâm để duyệt mã thư viện hiện có giải mã UTF-8, bạn sẽ thấy rằng đại đa số là sai trong ít nhất là cách tinh tế, và ít nhất 30% có lỗi nghiêm trọng về bảo mật nghiêm trọng. Ngoài ra, việc thực hiện GNU của 'iconv' là các đơn đặt hàng của cường độ quá chậm đối với các chuyển đổi ký tự-tại-một thời gian, mặc dù nó hoạt động ổn định (mặc dù không phù hợp với chủ ý)) cho chuyển đổi hàng loạt. –

+0

ảnh của tôi ở phiên bản nâng cao hơn: http://mercurial.intuxication.org/hg/cstuff/raw-file/tip/utf8_encode.c – Christoph

+2

Từ chối không phải ký tự có thể hữu ích cho ứng dụng của bạn, nhưng nó không phải là một phần của Đặc điểm kỹ thuật UTF-8 và nói chung không chính xác. UTF là bản đồ một-một giữa các chuỗi các đơn vị mã (byte hoặc các từ lớn hơn) và "Các giá trị vô hướng Unicode". Các giá trị Unicode Scalar chính xác là các số nguyên 0-0xD7FF và 0xE000-0x10FFFF. Đây là tất cả được xác định trong tiêu chuẩn Unicode mà bạn nên đọc trước khi cố gắng thực hiện một cái gì đó của riêng bạn. –

1

Nền tảng nào? Trên Windows, bạn có thể sử dụng WideCharToMultiByte (CP_UTF8, ...)

Có thể cho rằng điểm mã nguồn phải được mã hóa bằng UTF-16, điều đó có nghĩa là bạn phải có khả năng mã hóa như vậy. Trong một số trường hợp (cặp thay thế), nó không tầm thường.

Hiểu biết của tôi là bạn có một số văn bản trong một trang mã đã cho và bạn muốn chuyển đổi nó thành Unicode (UTF-16). Đúng? Một MultiByteToWideChar (codePage, sourceText, ...)/WideCharToMultiByte (CP_UTF8, utf16Text, ...) roundtrip sẽ thực hiện thủ thuật.

+0

Tôi đang làm việc trên linux. – chanux

+0

@chanux: Sau đó, bạn có thể sử dụng 'iconv', như được mô tả trong các câu trả lời khác. – Philipp

5

biểu tượng có thể được sử dụng tôi tính.

#include <iconv.h> 

iconv_t cd; 
char out[7]; 
wchar_t in = CODE_POINT_VALUE; 
size_t inlen = sizeof(in), outlen = sizeof(out); 

cd = iconv_open("utf-8", "wchar_t"); 
iconv(cd, (char **)&in, &inl, &out, &outlen); 
iconv_close(cd); 

Nhưng tôi sợ rằng wchar_t có thể không đại diện cho các điểm mã Unicode, nhưng giá trị tùy ý .. EDIT: Tôi đoán bạn có thể làm điều đó bằng cách đơn giản bằng cách sử dụng nguồn Unicode:

uint16_t in = UNICODE_POINT_VALUE; 
cd = iconv_open("utf-8", "ucs-2"); 
+2

Điều gì xảy ra nếu điểm mã không nằm trong BMP? ucs-2 không thể đại diện cho nó. Một wchar_t có thể không đủ theo nền tảng. Đây là lý do tại sao tôi nghĩ rằng giả định của OP về việc biết điểm mã là sai. Bởi vì sau đó, câu hỏi của mã hóa được sử dụng để đại diện cho nó được yêu cầu (UTF-32? UTF-16? Rõ ràng không phải là UTF-8) –

+1

Nếu '__STDC_ISO_10646__' được định nghĩa,' wchar_t' là một giá trị codepoint Unicode. Lưu ý rằng nếu 'wchar_t' là 16-bit, điều này ngụ ý rằng chỉ BMP được hỗ trợ; UTF-16 không phải là một khả năng. –

+1

Một 16 bit 'wchar_t' chắc chắn có thể được sử dụng trong các chuỗi được mã hóa UTF-16. Tất cả nó có nghĩa là bất kỳ giá trị codepoint bên ngoài của BMP sẽ được mã hóa bằng cách sử dụng 2 'wchar_t' thay thế các nhân vật cạnh nhau trong chuỗi được mã hóa, đó là tất cả. Windows API hoạt động trên chính xác loại dữ liệu này, và nó hoạt động tốt. –

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