stringstream с несколькими разделителями

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

Мне нужно читать в текстовой версии книги по одному слову, используя (любое количество) пробелов
' ' и (любое количество) небуквенных символов в качестве разделителей; поэтому любые пробелы или знаки препинания в любом количестве должны разделять слова. Вот как я это сделал, когда в качестве разделителя нужно было использовать только пробелы:

while(getline(inFile, line)) {
    istringstream iss(line);

    while (iss >> word) {
        table1.addItem(word);
    }
}

РЕДАКТИРОВАТЬ: пример прочитанного текста и то, как мне нужно его разделить.

"Если бы они знали, вы бы этого хотели, развлечение было бы".

Вот как должна быть разделена первая строка:

If

Oни

было

известный

ты

желал

it

в

развлекательная программа

бы

имеют

Текст будет содержать как минимум все стандартные знаки препинания, а также такие вещи, как многоточие ... двойное тире -- и т. д.

Как всегда, заранее спасибо.

РЕДАКТИРОВАТЬ:

Итак, использование второго строкового потока будет выглядеть примерно так?

while(getline(inFile, line)) {
    istringstream iss(line);

    while (iss >> word) {
        istringstream iss2(word);

        while(iss2 >> letter)  {
            if(!isalpha(letter))
                // do something?
        }
        // do something else?
        table1.addItem(word);
    }
}

person user3776749    schedule 23.11.2014    source источник
comment
Используйте поток для извлечения одного слова, игнорируя пробелы (по умолчанию). Затем поместите новый поток строк и извлекайте по одному символу за раз, используя std::isalnum, чтобы проверить, следует ли сохранять символ. Или используйте remove_if в строке.   -  person Neil Kirk    schedule 24.11.2014
comment
@Neil Kirk Исходное сообщение отредактировано. Как бы я отбросил/восстановил каждый символ после того, как определил, буква это или нет?   -  person user3776749    schedule 24.11.2014
comment
Не добавляйте его в выходную строку, если это не alnum. Буква должна быть char   -  person Neil Kirk    schedule 24.11.2014


Ответы (2)


Я не проверял это, так как сейчас передо мной нет компилятора g++, но он должен работать (кроме незначительных синтаксических ошибок C++)

while (getline(inFile, line))
{
    istringstream iss(line);

    while (iss >> word)
    {
        // check that word has only alpha-numeric characters
        word.erase(std::remove_if(word.begin(), word.end(), 
                                  [](char& c){return !isalnum(c);}),
                   word.end());
        if (word != "")
            table1.addItem(word);
    }
}
person vsoftco    schedule 23.11.2014
comment
Кажется, это работает, хотя я еще не проводил стресс-тест. Я думаю, что это будет более безопасная ставка, так как для этого требуется только ‹cstdlib›. У меня есть один вопрос, не могли бы вы точно объяснить, что здесь происходит: [](char& c){return !isalnum(c);} У меня есть достойная идея, и я узнаю различные части, но у меня нет контекста, чтобы точно определить, что она делает. - person user3776749; 24.11.2014
comment
@user3776749 user3776749 на самом деле это не работает, как если бы строка была чем-то вроде test.;works, тогда фрагмент удаляет из нее .; и выдает testworks одним словом. Приведенная выше функция называется лямбда-функцией (C++11) и возвращает значение true, если символ не является буквенно-цифровым. Я предполагаю, что лучше всего написать свой собственный токенизатор (или использовать Boost), хотя написание собственного не должно быть слишком большой проблемой. Ради забавы я написал себе токенизатор, и это очень просто, см.: github .com/vsoftco/tokenizer/blob/master/src/token.cpp Это дает вам общее представление. - person vsoftco; 24.11.2014
comment
@user3776749 user3776749 Итак, что вам нужно сделать, это прочитать word, начать его разбор и найти первый символ, который не является буквенно-цифровым, добавить слово, затем найти первый символ, который ЯВЛЯЕТСЯ буквенно-цифровым, и продолжать повторять до конца word. - person vsoftco; 24.11.2014
comment
Я обнаружил эту ошибку в своем тестировании, но, оглядываясь назад, я не верю, что это будет проблемой. Поскольку это книга, написанная на американском английском, между двумя разными словами всегда будет хотя бы один пробел. Это также будет корректно обрабатывать сокращения, т.е. не может, не и т. д. Спасибо за вашу помощь! - person user3776749; 24.11.2014
comment
@user3776749 user3776749 да, если есть гарантированный пробел, то вся боль ушла :) - person vsoftco; 24.11.2014
comment
Я также отмечу ваш токенизатор. Просто еще один инструмент в наборе инструментов! - person user3776749; 24.11.2014
comment
@ user3776749 убедитесь, что все в порядке, так как я думаю, что он также удаляет ' из can't - person vsoftco; 24.11.2014
comment
Да, но для моих целей это нормально. - person user3776749; 24.11.2014

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

$ cat kk.txt
If they had known;; you ... wished it, the entertainment.would have

Вы можете настроить поведение tokenizer, если это необходимо, но по умолчанию должно быть достаточно.

#include <iostream>
#include <fstream>
#include <string>

#include <boost/tokenizer.hpp>

int main()
{
  std::ifstream is("./kk.txt");
  std::string line;

  while (std::getline(is, line)) {
    boost::tokenizer<> tokens(line);

    for (const auto& word : tokens)
      std::cout << word << '\n';
  }

  return 0;
}

И наконец

$ ./a.out
If
they
had
known
you
wished
it
the
entertainment
would
have
person Jiří Pospíšil    schedule 23.11.2014
comment
Это интересное решение, и я сохраню его для будущего использования, но чтобы мой учитель не поднимал шума, я хотел бы придерживаться решений, которые требуют только очень простых библиотек функций. - person user3776749; 24.11.2014