С++ Как получить первую букву wstring

Это звучит как простая проблема, но C++ усложняет ее (по крайней мере, для меня): у меня есть wstring, и я хотел бы получить первую букву как объект wchar_t, а затем удалить эту первую букву из строки.

Это здесь не работает для символов, отличных от ASCII:

wchar_t currentLetter = word.at(0);  

Потому что он возвращает два символа (в цикле) для таких символов, как немецкие умляуты.

Здесь тоже не работает:

wchar_t currentLetter = word.substr(0,1);

error: no viable conversion from 'std::basic_string<wchar_t>' to 'wchar_t'

И это тоже:

wchar_t currentLetter = word.substr(0,1).c_str();

error: cannot initialize a variable of type 'wchar_t' with an rvalue of type 'const wchar_t *'

Любые другие идеи?

Ваше здоровье,

Мартин

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

#include <iostream>
using namespace std;

int main() {
    wstring word = L"für";
    wcout << word << endl;
    wcout << word.at(1) << " " << word[1] << " " << word.substr(1,1) << endl;

    wchar_t currentLetter;
    bool isLastLetter;

    do {
        isLastLetter = ( word.length() == 1 );
        currentLetter = word.at(0);
        wcout << L"Letter: " << currentLetter << endl;

        word = word.substr(1, word.length()); // remove first letter
    } while (word.length() > 0);

    return EXIT_SUCCESS;
}

Однако фактический результат, который я получаю:

ф?р ? ? ? Буква: f Буква: ? Буква: р

Исходный файл закодирован в UTF8, и кодировка консоли также установлена ​​​​на UTF8.


person marw    schedule 27.11.2013    source источник
comment
В чем именно проблема с первой версией? Можете ли вы опубликовать код для вашей проблемы с умлаутом?   -  person nvoigt    schedule 27.11.2013
comment
Строковые функции C++ по своей сути не поддерживают Unicode. Не ждите, что они поймут разницу между умлаутом и буквой.   -  person chris    schedule 27.11.2013
comment
wstring::substr() возвращает новый wstring, а не один символ.   -  person Jonathan Potter    schedule 27.11.2013


Ответы (1)


Вот решение, предоставленное Sehe:

#include <iostream>
#include <string>
#include <boost/regex/pending/unicode_iterator.hpp>

using namespace std;

template <typename C>
std::string to_utf8(C const& in)
{
    std::string result;
    auto out = std::back_inserter(result);
    auto utf8out = boost::utf8_output_iterator<decltype(out)>(out);

    std::copy(begin(in), end(in), utf8out);
    return result;
}

int main() {
    wstring word = L"für";

    bool isLastLetter;

    do {
        isLastLetter = ( word.length() == 1 );
        auto currentLetter = to_utf8(word.substr(0, 1));
        cout << "Letter: " << currentLetter << endl;

        word = word.substr(1, word.length()); // remove first letter
    } while (word.length() > 0);

    return EXIT_SUCCESS;
}

Вывод:

Letter: f

Letter: ü

Letter: r

Да, вам нужен Boost, но похоже, что вам все равно понадобится внешняя библиотека.

1

C++ не имеет представления о Unicode. Используйте внешнюю библиотеку, такую ​​как ICU (класс UnicodeString) или Qt (класс QString), обе поддерживают Unicode, включая UTF-8.

2

Поскольку UTF-8 имеет переменную длину, все виды индексации будут индексироваться в кодовых единицах, а не в кодовых точках. Произвольный доступ к кодовым точкам в последовательности UTF-8 невозможен из-за ее переменной длины. Если вам нужен произвольный доступ, вам нужно использовать кодировку фиксированной длины, например UTF-32. Для этого вы можете использовать префикс U в строках.

3

В стандарте языка C++ нет понятия явного кодирования. Он содержит только непрозрачное понятие «системной кодировки», для которой wchar_t является «достаточно большим» типом.

Чтобы преобразовать непрозрачную системную кодировку в явную внешнюю кодировку, вы должны использовать внешнюю библиотеку. Лучшей библиотекой будет iconv() (от WCHAR_T до UTF-8), которая является частью Posix и доступна на многих платформах, хотя в Windows функции WideCharToMultibyte гарантированно выдают кодировку UTF8.

C++11 добавляет новые литералы UTF8 в виде std::string s = u8"Hello World: \U0010FFFF";. Они уже есть в UTF8, но они не могут взаимодействовать с непрозрачной wstring, кроме как описанным мной способом.

4 (об исходных файлах, но все еще актуально)

Кодирование на C++ довольно сложно. Вот мое понимание этого.

Каждая реализация должна поддерживать символы из базового исходного набора символов. К ним относятся общие символы, перечисленные в §2.2/1 (§2.3/1 в C++11). Все эти символы должны помещаться в один символ. Кроме того, реализации должны поддерживать способ именования других символов, используя способ, называемый универсальными именами символов, и выглядеть как ￿ или \Uffffffff и могут использоваться для обозначения символов Unicode. Часть из них можно использовать в идентификаторах (перечисленных в Приложении E).

Это все хорошо, но отображение символов в файле на исходные символы (используемые во время компиляции) определяется реализацией. Это составляет используемую кодировку.

person Community    schedule 27.11.2013
comment
Большое спасибо за помощь. Однако я бы предпочел решение без зависимостей от внешних библиотек. Я не могу себе представить, что что-то настолько простое, как это, не включено в C++ из коробки. - person marw; 28.11.2013
comment
@marw На самом деле это не так просто, и, насколько я знаю (из источников, которые я цитировал), стандарт не совсем ясен. Если вам нужна согласованность, используйте библиотеку. - person ; 28.11.2013