Польские символы в std :: string - PullRequest
4 голосов
/ 22 ноября 2010

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

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

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

Ответы [ 3 ]

4 голосов
/ 22 ноября 2010

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

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

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

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

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

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

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

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

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

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

1 голос
/ 22 ноября 2010

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

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

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

Но вы не можете построить оператор switch / case для многобайтовых символов, используя char. Я бы рекомендовал использовать серию if с. Вы можете использовать Glibmm gunichar, но он не очень удобочитаемый (вы можете получить правильные значения Unicode для символов, используя таблицу из статьи по польскому алфавиту в Википедии ):

#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
0 голосов
/ 22 ноября 2010

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

...