Стрток и Чар *

У меня есть простой код, в котором я пытаюсь пройти через char* и разделить его на отдельные слова. Вот простой код, который у меня есть.

#include <iostream>
#include <stdio.h>
int main ()
{
   char * string1 = "- This is a test string";
   char * character_pointer;
   std::cout << "Splitting stringinto tokens:" << string1 << std::endl;
   character_pointer = strtok (string1," ");
   while (character_pointer != NULL)
   {
       printf ("%s\n", character_pointer);
       character_pointer = strtok (NULL, " ");
   }
   return 0;
}

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

Итак, мой вопрос: как пройти и найти каждое слово в char*. Для моей реальной программы, над которой я работаю, одна из моих библиотек возвращает абзац слов в виде const char*, и мне нужно составить основу каждого слова с помощью алгоритма определения основы (я знаю, как это сделать, я просто не знаю, как отправить каждое отдельное слово). слово стеммеру). Если кто-то может просто решить, как заставить код примера работать, я смогу это понять. Во всех онлайн-примерах используется char[] вместо string1 вместо char*, и я не могу этого сделать.


person DanRiz    schedule 30.04.2014    source источник
comment
Не используйте strtok. Он безнадежно сломан, а в C++ есть гораздо лучшие решения, использующие алгоритмы из стандартной библиотеки.   -  person James Kanze    schedule 30.04.2014
comment
Это не C++, а прежде всего C.   -  person DumbCoder    schedule 30.04.2014
comment
@DumbCoder Я никогда не использовал C и пытаюсь использовать это в C++, поэтому прошу прощения, если ошибся. Джеймс, как лучше решить эту проблему?   -  person DanRiz    schedule 30.04.2014
comment
@JamesKanze, как бы это сделать с C++ до C++11? Я пытался заменить strtok для токенизации, но так и не смог сделать это без снижения производительности. Я предполагаю, что тот факт, что strtok повторно использует уже выделенную строку, делает его довольно быстрым.   -  person Martin G    schedule 30.04.2014
comment
почему вы так смешиваете C и C++? В C используйте printf, а в C++ используйте cout.   -  person phuclv    schedule 30.04.2014
comment
@ scy7he С++ 11 здесь мало что добавляет. Вы бы использовали алгоритмы из <algorithm> (например, такие вещи, как std::find_first_of) и, возможно, конструктор с двумя итераторами из std::string.   -  person James Kanze    schedule 30.04.2014
comment
Кроме того, вы должны прочитать ошибку и исправить ее, чтобы она заработала. Если вы не можете исправить, то напишите об ошибке здесь   -  person phuclv    schedule 30.04.2014


Ответы (4)


Это самый простой (по коду) известный мне способ разбить строку на С++:

std::string string1 = "- This is a test string";
std::string word;
std::istringstream iss(string1);
// by default this splits on any whitespace
while(iss >> word) {
    std::cout << word << '\n';
}

или вот так, если вы хотите указать разделитель.

while(std::getline(iss, word, ' ')) {
    std::cout << word << '\n';
}
person eerorika    schedule 30.04.2014

Вот исправленная версия, попробуйте:

#include <iostream>
#include <stdio.h>
#include <cstring>
int main ()
{
   char string1[] = "- This is a test string";
   char * character_pointer;
   std::cout << "Splitting stringinto tokens:" << string1 << std::endl;
   character_pointer = strtok (string1," ");
   while (character_pointer != NULL)
   {
       printf ("%s\n", character_pointer);
       character_pointer = strtok (NULL, " ");
   }
   return 0;
}
person Dr. Debasish Jana    schedule 30.04.2014

Есть разные способы сделать это в C++.

Если пространство ограничено, вы можете получить токены следующим образом:

std::string text = "- This is a test string";
std::istringstream ss(text);
std::vector<std::string> tokens;
std::copy(std::istream_iterator<std::string>(ss),
          std::istream_iterator<std::string>(),
          std::back_inserter<std::vector<std::string>>(tokens));

Вы также можете токенизировать строку в C++ с помощью регулярных выражений.

std::string text = "- This is a test string";
std::regex pattern("\\s+");
std::sregex_token_iterator it(std::begin(text), std::end(text), pattern, -1);
std::sregex_token_iterator end;
for(; it != end; ++it)
{
   std::cout << it->str() << std::endl;
}
person Marius Bancila    schedule 30.04.2014
comment
Обратите внимание, что поддержка <regex> была добавлена ​​в libstdc++ в версии 4.9 gcc. - person eerorika; 30.04.2014
comment
Я не видел никакой ссылки на gcc, но да, это правда. - person Marius Bancila; 30.04.2014
comment
Ваше предположение также не соответствует действительности. Код ОП разрывается на пробеле, ваш — на всем, что не является буквой или дефисом. - person DevSolar; 30.04.2014
comment
Да, спасибо, что указали на это. Я обновил ответ. Новая версия должна быть правильной. - person Marius Bancila; 30.04.2014
comment
Для чего-то простого, как он делает (и на самом деле большую часть того, что может сделать strtok), регулярные выражения излишни, а использование istream слишком тяжело и не очень гибко. Такие вещи, как std::find_first_of, std::search и так далее, намного проще. - person James Kanze; 30.04.2014

Забудьте о strtok. Чтобы получить именно то, к чему вы стремитесь:

std::string const source = "- This is a test string";
std::vector<std::string> tokens;
std::string::const_iterator start = source.begin();
std::string::const_iterator end   = source.end();
std::string::const_iterator next  = std::find( start, end, ' ' );
while ( next != end ) {
    tokens.push_back( std::string( start, next ) );
    start = next + 1;
    next = std::find( start, end, ' ' );
}
tokens.push_back( std::string( start, next ) );

Конечно, это можно изменить как угодно: вы можете использовать std::find_first_of, если вам нужно более одного разделителя, или std::search, если вам нужен многосимвольный разделитель, или даже std::find_if для произвольного теста (с лямбдой, если вы есть С++11). И в большинстве случаев, когда вы анализируете, вы можете просто передать два итератора, вместо того, чтобы создавать подстроку; вам нужно создать подстроку только тогда, когда вы хотите где-то сохранить извлеченный токен.

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

person James Kanze    schedule 30.04.2014