2010-11-22 3 views
4

У меня проблема. Я пишу приложение на польском языке (с, конечно, польский) для Linux, и при компиляции я получаю 80 предупреждений. Это просто «предупреждение: многосимвольная символьная константа» и «предупреждение: значение метки ярлыка превышает максимальное значение для типа». Я использую std :: string.Польские символы в std :: string

Как заменить класс std :: string?

Пожалуйста, помогите. Спасибо заранее. С уважением.

ответ

4

std::string не определите конкретное кодирование. Таким образом, вы можете сохранить любую последовательность из байт. Есть тонкости, о которых следует знать:

  1. .c_str() возвращает буфер с нулевым завершением. Если ваш набор символов допускает нулевые байты, не передавайте эту строку на функции, которые принимают параметр const char* без длины, или ваши данные будут усечены.
  2. A char не является символом, но ** байт. ИМХО, это самая проблемная номенклатура в истории вычислений. Обратите внимание, что wchar_t обязательно содержит полный символ, в зависимости от нормализации UTF-16.
  3. .size() и .length() вернет число байт, а не количество символов.

[править] предупреждения о case меток связаны с выпуском (2). Вы используете оператор switch с многобайтовыми символами, используя тип char, который не может содержать более одного байта. [/ править]

Таким образом, вы можете использовать std::string в вашем приложении, при условии, что вы уважаете эти три правила. Существуют тонкости, связанные с STL, включая std::find(), что является следствием этого.Для правильной поддержки Unicode из-за форм нормализации вам нужно использовать еще несколько умных алгоритмов соответствия строк.

Однако при написании приложений на любом языке, который использует символы, отличные от ASCII (если вы параноидны, считайте это чем-то вне [0, 128)), вам нужно знать кодировки в разных источниках текстовых данных.

  1. исходного файла кодирования не может быть указан, и может быть изменена с помощью опции компилятора. Любой строковый литерал будет подчиняться этому правилу. Думаю, именно поэтому вы получаете предупреждения.
  2. Вы получите множество кодировок символов из внешних источников (файлы, пользовательский ввод и т. Д.). Когда этот источник указывает кодировку, или вы можете получить ее из какого-то внешнего источника (т. Е. Запрашивая у пользователя, который импортирует данные), тогда это проще. Многие (более новые) интернет-протоколы налагают ASCII или UTF-8, если не указано иное.

Эти два вопроса не рассматриваются каким-либо конкретным классом строк. Вам просто нужно преобразовать все внешние источники во внутреннюю кодировку. Я предлагаю UTF-8 все время, но особенно на Linux из-за собственной поддержки. Я настоятельно рекомендую поместить ваши строковые литералы в файл сообщения, чтобы забыть о проблеме (1) и только иметь дело с проблемой (2).

Я не предлагаю использовать std::wstring на Linux, так как 100% нативных API для использования сигнатур функций с const char* и имеют прямую поддержку для UTF-8. Если вы используете какой-либо строковый класс, основанный на wchar_t, вам нужно будет конвертировать в/из std::wstring без остановок и в итоге получить что-то не так, вместо того, чтобы делать все медленнее (er).

Если вы пишете приложение для Windows, я бы предложил точно противоположное, потому что все родные API используют const wchar_t* подписи. Версия ANSI таких функций выполняет внутреннее преобразование в/from const wchar_t*.

Некоторые «портативные» библиотеки/языки используют разные представления, основанные на платформе. Они используют UTF-8 с char на Linux и UTF-16 с wchar_t на Windows. Я помню, как читал этот трюк в реализации ссылок на Python, но статья была довольно старой. Я не уверен, что это правда.

-1

std::string предназначено для строк ASCII. Так как ваши полирующие строки не подходят, вы должны использовать std::wstring.

+0

Я слышал, что `std :: wstring` почти никогда не будет использоваться в Linux. Но я не совсем уверен, почему. – rhino 2010-11-22 14:58:39

+0

-1: `std :: string` не определяет конкретный набор символов, но есть случаи краев, которые следует учитывать при хранении в нем многобайтных строк. См. Мой комментарий к ответу `jikv`. – 2010-11-22 20:15:50

1

В linux вы должны использовать многобайтовый класс строк, предоставляемый каркасом, который вы используете.

Я бы рекомендовал Glib :: ustring из фреймворка glibmm, который хранит строки в кодировке UTF-8. Если исходные файлы в UTF-8, а затем с помощью многобайтовых строкового литерала в коде так же легко, как:

ustring alphabet("aąbcćdeęfghijklłmnńoóprsśtuwyzźż"); 

Но вы не можете построить переключатель/случай заявления о мультибайтных символах с помощью char. Я бы рекомендовал использовать серию if s. Вы можете использовать Glibmm-х gunichar, но это не очень читаемый (Вы можете получить правильные значения Юникода для символов с помощью таблицы из article on Polish alphabet in Wikipedia):

#include <glibmm.h> 
#include <iostream> 

using namespace std; 

int main() 
{ 
     Glib::ustring alphabet("aąbcćdeęfghijklłmnńoóprsśtuwyzźż"); 
     int small_polish_vovels_with_diacritics_count = 0; 
     for (int i=0; i<alphabet.size(); i++) { 
       switch (alphabet[i]) { 
         case 0x0105: // ą 
         case 0x0119: // ę 
         case 0x00f3: // ó 
           small_polish_vovels_with_diacritics_count++; 
           break; 
         default: 
           break; 
       } 
     } 
     cout << "There are " << small_polish_vovels_with_diacritics_count 
       << " small polish vovels with diacritics in this string.\n"; 
     return 0; 
} 

Вы можете компилировать это с помощью:

g++ `pkg-config --cflags --libs glibmm-2.4` progname.cc -o progname 
Смежные вопросы