C++: UTF-8 の文字列を1文字ずつ表示する (std::string)

std::u32string、std::u16string などで1文字ずつ表示することを行ったが、今度は std::string もやってみた。コードをかんたんにするために、不正なバイト列を考慮していない。

#include <iostream>
#include <string>

void print_each_char(std::string);

int main(void)
{
    using namespace std;
    string str = u8"𠮷野家のコピペ";
    print_each_char(str);

    return 0;
}

void print_each_char(std::string str)
{
    using namespace std;

    int pos;
    unsigned char lead; 
    int char_size;

   for (pos = 0; pos < str.size(); pos += char_size) {
   
        lead = str[pos];

        if (lead < 0x80) {
            char_size = 1;
        } else if (lead < 0xE0) {
            char_size = 2;
        } else if (lead < 0xF0) {
            char_size = 3;
        } else {
            char_size = 4;
        }

        cout << str.substr(pos, char_size) << '\n';
    }

}

イテレーターを使うと次のようになる。

#include <iostream>
#include <string>

void print_each_char(std::string);

int main(void)
{
    using namespace std;
    string str = u8"𠮷野家のコピペ";
    print_each_char(str);

    return 0;
}

void print_each_char(std::string str)
{
    using namespace std;

    unsigned char lead; 
    int char_size = 0;

    for (string::iterator it = str.begin(); it != str.end(); it += char_size) {

        lead = *it;

        if (lead < 0x80) {
            char_size = 1;
        } else if (lead < 0xE0) {
            char_size = 2;
        } else if (lead < 0xF0) {
            char_size = 3;
        } else {
            char_size = 4;
        }

        cout << str.substr(distance(str.begin(), it), char_size) << '\n';

    }

}

戻り値にタプルを使った例は次のとおり。

#include <iostream>
#include <string>

std::tuple<std::string, int> utf8_next_char(std::string str, int str_size, int pos);

int main(void)
{
    using namespace std;

    string str = u8"あいうえお";
    tuple<string, int> t;
    int str_size = str.size();

    int pos = 0;
    string buf;
    int buf_size = 0;

    for (int pos = 0; pos < str_size; pos += buf_size) {
        t = utf8_next_char(str, str_size, pos);
        buf = get<0>(t);
        buf_size = get<1>(t);
        cout << buf << '\n';
    }

    return 0;
}

std::tuple<std::string, int> utf8_next_char(std::string str, int str_size, int pos)
{
    using namespace std;
    unsigned char c;

    string buf;
    int buf_size;

    if (pos >= str_size) {
        return make_tuple(u8"?", pos);
    }

    c = str[pos];

    if (c < 0x80) {
        buf_size = 1;
    } else if (c < 0xE0) {
        buf_size = 2;
    } else if (c < 0xF0){
        buf_size = 3;
    } else {
        buf_size = 4;
    }

    buf = str.substr(pos, buf_size);

    return  make_tuple(buf, buf_size);
}