Как разбить строку по смайликам в C ++ - PullRequest
6 голосов
/ 06 августа 2020

Я пытаюсь взять строку смайлов и разбить их на вектор каждого смайлика

Учитывая строку:

std::string emojis = "????????";

Я пытаюсь получить:

std::vector<std::string> splitted_emojis = {"?", "?", "?", "?", "?", "?", "?", "?"};

Edit

Пытался сделать:

std::string emojis = "????????";
std::vector<std::string> splitted_emojis;
size_t pos = 0;
std::string token;
while ((pos = emojis.find("")) != std::string::npos)
{
    token = emojis.substr(0, pos);
    splitted_emojis.push_back(token);
    emojis.erase(0, pos);
}

Но вроде через пару секунд выдает terminate called after throwing an instance of 'std::bad_alloc'.
При попытке проверить, сколько смайликов в строке, используя:

std::string emojis = "????????";
std::cout << emojis.size() << std::endl; // returns 32

, он возвращает большее число, которое, как я полагаю, является данными Unicode. Я не слишком много знаю о данных Unicode, но я пытаюсь выяснить, как проверить, когда данные эмодзи начинаются и заканчиваются, чтобы иметь возможность разделить строку на каждый эмодзи

1 Ответ

2 голосов
/ 06 августа 2020

Я бы определенно рекомендовал вам использовать библиотеку с лучшей поддержкой Unicode (все большие фреймворки это делают), но в крайнем случае вы можете обойтись, зная, что кодировка UTF-8 распространяет символы Unicode на несколько байтов, и что первый биты первого байта определяют, из скольких байтов состоит символ.

Я украл функцию из boost . Функция split_by_codepoint использует итератор над входной строкой и создает новую строку с использованием первых N байтов (где N определяется функцией подсчета байтов) и помещает ее в вектор ret.

// Taken from boost internals
inline unsigned utf8_byte_count(uint8_t c)
{
  // if the most significant bit with a zero in it is in position
  // 8-N then there are N bytes in this UTF-8 sequence:
  uint8_t mask = 0x80u;
  unsigned result = 0;
  while(c & mask)
  {
    ++result;
    mask >>= 1;
  }
  return (result == 0) ? 1 : ((result > 4) ? 4 : result);
}

std::vector<std::string> split_by_codepoint(std::string input) {
  std::vector<std::string> ret;
  auto it = input.cbegin();
  while (it != input.cend()) {
    uint8_t count = utf8_byte_count(*it);
    ret.emplace_back(std::string{it, it+count});
    it += count;
  }
  return ret;
}

int main() {
    std::string emojis = u8"????????";
    auto split = split_by_codepoint(emojis);
    std::cout << split.size() << std::endl;
}

Обратите внимание, что эта функция просто разбивает строку на строки UTF-8, содержащие по одной кодовой точке каждая. Определение того, является ли символ эмодзи, оставлено в качестве упражнения: UTF-8 декодирует любые 4-байтовые символы и проверяет, находятся ли они в правильном диапазоне.

...