Как получить вектор слов из строки? - PullRequest
2 голосов
/ 14 марта 2020

Я хочу хранить слова, разделенные пробелами, в виде одиночных строковых элементов в векторе. Входные данные - это строка, которая может заканчиваться или не заканчиваться символом (запятая, точка и т. Д. c.) Все символы также будут разделяться пробелами.

Я создал эту функцию, но она не верните мне вектор слов.

vector<string> single_words(string sentence)
{
    vector<string> word_vector;
    string result_word;

    for (size_t character = 0; character < sentence.size(); ++character)
    {
        if (sentence[character] == ' ' && result_word.size() != 0)
        {
            word_vector.push_back(result_word);
            result_word = "";
        }
        else
            result_word += character;
    }
    return word_vector;
}

Что я сделал не так?

Ответы [ 3 ]

2 голосов
/ 15 марта 2020

Ваша проблема уже решена с помощью ответов и комментариев.

Я хотел бы предоставить вам дополнительную информацию о том, что такая функциональность уже существует в C ++.

Вы можете воспользоваться Тот факт, что оператор извлечения извлекает из потока разделенные токены. Поскольку std::string не является потоком, мы можем сначала поместить строку в std::istringstream, а затем извлечь из этого потока v ie std:::istream_iterator.

Мы могли бы сделать жизнь еще проще.

Уже около 10 лет у нас есть специальная специальная функциональность C ++ для разбиения строк на токены, специально разработанная для этой цели. std::sregex_token_iterator. И поскольку у нас есть такая выделенная функция, мы должны просто использовать ее.

Идея, лежащая в основе этой концепции, заключается в концепции итератора. В C ++ у нас есть много контейнеров и всегда итераторов, чтобы перебирать похожие элементы в этих контейнерах. И строка с похожими элементами (токенами), разделенными разделителем, также может рассматриваться как такой контейнер. А с помощью std::sregex:token_iterator мы можем перебирать элементы / токены / подстроки строки, эффективно разбивая ее на части.

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

См. Некоторые примеры ниже:

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
#include <regex>

const std::regex delimiter{ " " };
const std::regex reWord{ "(\\w+)" };

int main() {

    // Some debug print function
    auto print = [](const std::vector<std::string>& sv) -> void {
        std::copy(sv.begin(), sv.end(), std::ostream_iterator<std::string>(std::cout, "\n")); std::cout << "\n"; };

    // The test string
    std::string test{ "word1 word2 word3 word4." };

    //-----------------------------------------------------------------------------------------
    // Solution 1: use istringstream and then extract from there
    std::istringstream iss1(test);

    // Define a vector (CTAD), use its range constructor and, the std::istream_iterator as iterator
    std::vector words1(std::istream_iterator<std::string>(iss1), {});

    print(words1); // Show debug output

    //-----------------------------------------------------------------------------------------
    // Solution 2: directly use dedicated function sregex_token iterator
    std::vector<std::string> words2(std::sregex_token_iterator(test.begin(), test.end(), delimiter, -1), {});

    print(words2); // Show debug output

    //-----------------------------------------------------------------------------------------
    // Solution 3: directly use dedicated function sregex_token iterator and look for words only
    std::vector<std::string> words3(std::sregex_token_iterator(test.begin(), test.end(), reWord, 1), {});

    print(words3); // Show debug output

    //-----------------------------------------------------------------------------------------
    // Solution 4: Use such iterator in an algorithm, to copy data to a vector

    std::vector<std::string> words4{};
    std::copy(std::sregex_token_iterator(test.begin(), test.end(), reWord, 1), {}, std::back_inserter(words4));

    print(words4); // Show debug output

    //-----------------------------------------------------------------------------------------
    // Solution 5: Use such iterator in an algorithm for direct output
    std::copy(std::sregex_token_iterator(test.begin(), test.end(), reWord, 1), {}, std::ostream_iterator<std::string>(std::cout,"\n"));

    return 0;
}

2 голосов
/ 14 марта 2020

Вы добавили индекс вместо символа:

vector<string> single_words(string sentence)
{
    vector<string> word_vector;
    string result_word;

    for (size_t i = 0; i < sentence.size(); ++i)
    {
        char character = sentence[i];
        if (character == ' ' && result_word.size() != 0)
        {
            word_vector.push_back(result_word);
            result_word = "";
        }
        else
            result_word += character;
    }
    return word_vector;
}
0 голосов
/ 15 марта 2020

Поскольку ваша ошибка произошла только по той причине, что вы назвали свою переменную итератора character, хотя это на самом деле не символ, а скорее итератор или индекс, я хотел бы предложить использовать l с ранжированной базой oop здесь, поскольку это позволяет избежать такого рода путаницы. Чистое решение, очевидно, состоит в том, чтобы делать то, что сказал @ArminMontigny, но я предполагаю, что вам запрещено использовать stringstream s. Код будет выглядеть так:

#include <iostream>
#include <string>
#include <vector> 
using namespace std;

vector<string> single_words(string sentence)
{
    vector<string> word_vector;
    string result_word;

    for (char& character: sentence) // Now `character` is actually a character.
    {
        if (character==' ' && result_word.size() != 0)
        {
            word_vector.push_back(result_word);
            result_word = "";
        }
        else
            result_word += character;
    }
    word_vector.push_back(result_word); // In your solution, you forgot to push the last word into the vector.
    return word_vector;
}

int main() {
    string sentence="Maybe try range based loops";
    vector<string> result= single_words(sentence);
    for(string& word: result)
      cout<<word<<" ";
    return 0;
}
...