Как работать с UTF-8 в C++, Преобразование из других кодировок в UTF-8
Я не знаю, как решить это:
Представьте, у нас есть 4 сайта:
- A: UTF-8
- B: ISO-8859-1
- C: ASCII
- D: UTF-16
Моя программа, написанная на C++, выполняет следующие действия: загружает веб-сайт и анализирует его. Но это должно понимать содержание. Моя проблема не в разборе, который выполняется с помощью ASCII-символов, таких как ">"
или же "<"
,
Проблема в том, что программа должна найти все слова из текста сайта. Слово - это любая комбинация буквенно-цифровых символов. Затем я отправляю эти слова на сервер. База данных и веб-интерфейс используют UTF-8. Итак, мои вопросы:
- Как я могу преобразовать любую (или наиболее часто используемую) кодировку символов в UTF-8?
- Как я могу работать с UTF-8-строк в C++? Я думаю
wchar_t
не работает, потому что его длина составляет 2 байта. Кодовые точки в UTF-8 имеют длину до 4 байтов... - Есть ли такие функции, как
isspace()
,isalnum()
,strlen()
,tolower()
для таких UTF-8-струн?
Пожалуйста, обратите внимание: я не делаю вывод (например, std::cout
) в C++. Просто отфильтровываю слова и отправляю их на сервер.
Я знаю о UTF8-CPP, но он не имеет is*()
функции. И, как я читал, он не конвертируется из других кодировок в UTF-8. Только от UTF- * до UTF-8.
Редактировать: я забыл сказать, что программа должна быть переносимой: Windows, Linux, ...
4 ответа
Как я могу преобразовать любую (или наиболее часто используемую) кодировку символов в UTF-8?
ICU (Международные компоненты для Unicode) является решением здесь. Как правило, это последнее слово в поддержке Unicode. Даже Boost.Locale и Boost.Regex используют его, когда дело доходит до Unicode. См. Мой комментарий к ответу Дори Зидон о том, почему я рекомендую использовать ICU напрямую, а не обертками (например, Boost).
Вы создаете конвертер для данной кодировки...
#include <ucnv.h>
UConverter * converter;
UErrorCode err = U_ZERO_ERROR;
converter = ucnv_open( "8859-1", &err );
if ( U_SUCCESS( error ) )
{
// ...
ucnv_close( converter );
}
... а затем использовать класс UnicodeString как собственный.
Я думаю, что wchar_t не работает, потому что его длина составляет 2 байта.
Размер wchar_t
определяется реализацией. AFAICR, Windows - 2 байта (UCS-2 / UTF-16, в зависимости от версии Windows), Linux - 4 байта (UTF-32). В любом случае, так как стандарт не определяет семантику Unicode для wchar_t
, используя это непереносимые догадки. Не угадайте, используйте ICU.
Существуют ли такие функции, как isspace(), isalnum(), strlen(), tolower() для таких строк UTF-8?
Не в их кодировке UTF-8, но вы все равно не используете это внутренне. UTF-8 хорош для внешнего представления, но внутренне UTF-16 или UTF-32 - лучший выбор. Вышеупомянутые функции существуют для кодовых точек Unicode (т. Е. UChar32); ссылка учар.ч.
Обратите внимание: я не делаю вывод (например, std::cout) в C++. Просто отфильтровываю слова и отправляю их на сервер.
Проверьте BreakIterator.
Редактировать: я забыл сказать, что программа должна быть переносимой: Windows, Linux, ...
Если я еще этого не сказал, используйте ICU и избавьте себя от множества неприятностей. Даже если на первый взгляд это может показаться немного тяжеловесным, это лучшая из существующих реализаций, она чрезвычайно портативна (использую ее в Windows, Linux и AIX сама), и вы будете использовать ее снова и снова и снова в проектах, чтобы Приходите, поэтому время, потраченное на изучение его API, не теряется.
Не уверен, что это даст вам все, что вы ищете, но это может немного помочь. Вы пробовали смотреть на:
1) Библиотека Boost.Locale? Boost.Locale был выпущен в Boost 1.48(15 ноября 2011 г.), что упрощает конвертацию из UTF8/16 и обратно.
Вот несколько удобных примеров из документов:
string utf8_string = to_utf<char>(latin1_string,"Latin1");
wstring wide_string = to_utf<wchar_t>(latin1_string,"Latin1");
string latin1_string = from_utf(wide_string,"Latin1");
string utf8_string2 = utf_to_utf<char>(wide_string);
2) Или при преобразованиях являются частью C++11?
#include <codecvt>
#include <locale>
#include <string>
#include <cassert>
int main() {
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert;
std::string utf8 = convert.to_bytes(0x5e9);
assert(utf8.length() == 2);
assert(utf8[0] == '\xD7');
assert(utf8[1] == '\xA9');
}
Как я могу работать с UTF-8-строк в C++? Я думаю, что wchar_t не работает, потому что его длина составляет 2 байта. Кодовые точки в UTF-8 имеют длину до 4 байтов...
Это легко, есть проект с именем tinyutf8, который является заменой для std::string
/std::wstring
,
Тогда пользователь может элегантно работать с кодовыми точками, в то время как их представление всегда кодируется в char
s.
Как я могу преобразовать любую (или наиболее часто используемую) кодировку символов в UTF-8?
Возможно, вы захотите взглянуть на std::codecvt_utf8
и одинаковые шаблоны из <codecvt>
(C++, 11).
UTF-8 - это кодировка, которая использует несколько байтов для не-ASCII (7-битный код) с использованием 8-го бита. Как таковой, вы не найдете '\'
, '/'
внутри многобайтовой последовательности. А также isdigit
работает (правда не арабский и прочие цифры).
Это расширенный набор ASCII и может содержать все символы Unicode, поэтому определенно использовать с char и string.
Проверьте заголовки HTTP (без учета регистра); они находятся в ISO-8859-1 и предшествуют пустой строке, а затем содержанию HTML.
Content-Type: text/html; charset=UTF-8
Если нет, там также может быть
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="UTF-8"> <!-- HTML5 -->
ISO-8859-1 - это латиница 1, и вам лучше преобразовать из Windows-1252 расширение Windows Latin-1, используя 0x80 - 0xBF для некоторых специальных символов, таких как кавычки и тому подобное. Даже браузеры на MacOS поймут это, хотя был указан ISO-8859-1.
Библиотеки конвертации: уже упоминалось @syam.
преобразование
Давайте не будем рассматривать UTF-16. Можно прочитать заголовки и начать до мета-оператора для набора символов как однобайтовые символы.
Преобразование из однобайтовой кодировки в UTF-8 может происходить через таблицу. Например, сгенерированный с Java: const char* table[]
индексируется символом.
table[157] = "\xEF\xBF\xBD";
public static void main(String[] args) {
final String SOURCE_ENCODING = "windows-1252";
byte[] sourceBytes = new byte[1];
System.out.println(" const char* table[] = {");
for (int c = 0; c < 256; ++c) {
String comment = "";
System.out.printf(" /* %3d */ \"", c);
if (32 <= c && c < 127) {
// Pure ASCII
if (c == '\"' || c == '\\')
System.out.print("\\");
System.out.print((char)c);
} else {
if (c == 0) {
comment = " // Unusable";
}
sourceBytes[0] = (byte)c;
try {
byte[] targetBytes = new String(sourceBytes, SOURCE_ENCODING).getBytes("UTF-8");
for (int j = 0; j < targetBytes.length; ++j) {
int b = targetBytes[j] & 0xFF;
System.out.printf("\\x%02X", b);
}
} catch (UnsupportedEncodingException ex) {
comment = " // " + ex.getMessage().replaceAll("\\s+", " "); // No newlines.
}
}
System.out.print("\"");
if (c < 255) {
System.out.print(",");
}
System.out.println();
}
System.out.println(" };");
}