Разбить std :: string умлаутами на символы - PullRequest
0 голосов
/ 28 ноября 2018

Чтобы разделить std::string на символы, я могу просто перебрать строку.Тем не менее, это не работает, если строка содержит немецкие умлауты ä,ö,ü,ß,....

Я нашел решение, используя std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>, который работает для меня.Но это кажется слишком сложным, есть ли более приятное решение?

#include <string>
#include <vector>
#include <iostream>
#include <locale>
#include <codecvt>

// Works with umlauts:
std::vector<std::string> split_wstring(const std::string &word) {
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
    std::wstring wword = converter.from_bytes(word);
    std::vector<std::string> characters;
    for (auto iter : wword) {
        characters.push_back(converter.to_bytes(iter));
    }
    return characters;
}

// Works fine for english words but fails for umlauts:
std::vector<std::string> split_string(const std::string &word) {
    std::vector<std::string> characters;
    for (auto iter : word) {
        characters.push_back(&iter);
    }
    return characters;
}

int main() {
    for (auto c : split_string("AbcühßtÖ")) {
        std::cout << "Split String: " << c << std::endl;
    }
    for (auto c : split_wstring("AbcühßtÖ")) {
        std::cout << "Split W-String: " << c << std::endl;
    }
}

(я разбил слова на std :: strings длины 1 вместо символов, потому что в любом случае мне нужно, чтобы они были std :: strings)

Вывод:

Split String: A
Split String: b
Split String: c
Split String: �
Split String: �
Split String: h
Split String: �
Split String: �
Split String: t
Split String: �
Split String: �
Split W-String: A
Split W-String: b
Split W-String: c
Split W-String: ü
Split W-String: h
Split W-String: ß
Split W-String: t
Split W-String: Ö

Похожий пост: C ++ итерация строки utf-8 со смешанной длиной символов Решение заключается в использовании длинного кода третьей стороны,Я думаю, что мое решение с конвертером wstring уже лучше.

1 Ответ

0 голосов
/ 29 ноября 2018

Спасибо за все ответы, они помогли мне понять, что преобразование в Utf-16 или Utf-32 не лучший подход.

Я еще раз взглянул на этот ответ инаписал итератор на его основе.Я мог бы подтвердить, что он работает для строк utf-8 с символами различной длины байтов.

#include <string>
#include <vector>
#include <iostream>


class UtfIterator {
public:
    std::string::const_iterator str_iter;
    size_t cplen;

    UtfIterator(const std::string::const_iterator str_iter) : str_iter(str_iter) {
        find_cplen();
    }

    std::string operator*() const {
        return std::string(str_iter, str_iter + cplen);
    }

    UtfIterator& operator++() {
        str_iter += cplen;
        find_cplen();
        return *this;
    }

    bool operator!=(const UtfIterator &o) const {
        return this->str_iter != o.str_iter;
    }
private:
    void find_cplen() {
        cplen = 1;
        if((*str_iter & 0xf8) == 0xf0) cplen = 4;
        else if((*str_iter & 0xf0) == 0xe0) cplen = 3;
        else if((*str_iter & 0xe0) == 0xc0) cplen = 2;
        // if(iter + cplen > text.length()) cplen = 1;
    }
};

int main() {
    std::string s("今天周五123äöÜß");
    for (UtfIterator iter(s.begin()); iter != UtfIterator(s.end()); ++iter) {
        std::cout << "char: " << *iter << std::endl;
    }
}

Об этой строке без комментариев: Насколько я понимаю, ее цель состоит в том, чтобы найти битые строки Utf-8, в которых отсутствуют байтыв конце.Я не мог найти способ реализовать это в своем итераторе, не зная итератор end().Есть идеи?

...