将带有变音符的std :: string拆分为字符

时间:2018-11-28 14:46:03

标签: c++ unicode utf-8 split stdstring

要将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;
    }
}

(我将单词分割为长度为1的std :: string而不是char,因为无论如何我都需要将它们设为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: Ö

有类似的帖子:Update by query API 解决方案是使用冗长的第三方代码。我认为wstring转换器的解决方案已经更好了。

1 个答案:

答案 0 :(得分:0)

感谢所有答复,他们帮助我理解了转换为Utf-16或Utf-32并不是最好的方法。

我再次查看了this answer,并基于它编写了一个迭代器。我可以确认它适用于字符长度不同的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()迭代器的情况下,我找不到在迭代器中实现此方法的方法。有什么想法吗?