CPP C++ logo

В прошлом году мне понадобилось доработать токенизатор в моем движке. Поэтому я быстро набросал новую простейшую версию.

Токенизатор хранит лишь начало/конец токена аля std::string_view. Поддерживается UTF-8. Поддерживает произвольный набор разделителей и их произвольную длину. Может быть достаточно легко доработан до поддержки японского, корейского, тайского и прочих языков.

Тут выкладываю лишь свой набросок токенизатора. Доработанная версия, вошедшая в движок, была сделана на его основе.

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

class Tokenizer
{
public:
    using DelimetersList = std::vector<std::string>;

    Tokenizer(const DelimetersList& delimiters)
        : m_delimiters(delimiters)
    {
    }

    void tokenize(const std::string& str)
    {
        m_tokens.clear();

        size_t start = 0;
        size_t end = 0;

        while (end != str.length())
        {
            auto delimiter = findDelimiter(str, start);
            end = delimiter.pos;

            m_tokens.push_back({ start, end - start });

            start = end + delimiter.length;
        }
    }

    struct Token
    {
        size_t begin;
        size_t length;
    };

    using TokensList = std::vector<Token>;

    const TokensList& getTokens() const
    {
        return m_tokens;
    }

private:
    struct Delimiter
    {
        size_t pos;
        size_t length;
    };

    Delimiter findDelimiter(const std::string& str, size_t start) const
    {
        size_t minPos = str.length();
        size_t length = 0;

        for (auto& delimiter : m_delimiters)
        {
            auto pos = str.find(delimiter, start);
            if (pos < minPos)
            {
                minPos = pos;
                length = delimiter.length();
            }
        }

        return { minPos, length };
    }

private:
    const DelimetersList m_delimiters;

private:
    TokensList m_tokens;
};

int main()
{
    std::string s = "お客#様のレビ#ュー\nはゲー\nム#の改善に役#立ちます!";

    std::cout << "string: \n" << s << "\n----\n" << std::endl;

    Tokenizer tokenizer({ " ", "\n", "\r", "#" });
    tokenizer.tokenize(s);

    for (auto& t : tokenizer.getTokens())
    {
        std::cout << s.substr(t.begin, t.length) << std::endl;
    }

    return 0;
}