Я пытаюсь создать программу, которая принимает данные из .txt или аналогичного файла и запрашивает у пользователя слово для поиска. Выходные данные должны показывать ключевое слово в контексте с двумя словами, которые были как перед ним, так и за ним. (Пример: ключевое слово: мальчик будет выводить «и мальчик убежал») Я могу найти все экземпляры ключевого слова в файле с помощью функции equal_range (), однако я не знаю, как перебирать данные на карте чтобы получить доступ к другим словам для контекста. Вот мой код до сих пор:
typedef multimap<string, int> templateMap;
templateMap wordMap;
typedef pair<templateMap::iterator, templateMap::iterator> searchTemplate;
searchTemplate search;
typedef pair<templateMap::const_iterator, templateMap::const_iterator> innerIteratorTemplate;
multimap<string, int>::iterator tempMap;
string tempWord;
string keyword;
// omitted code
for (size_t i = 0; !inData.eof(); i++)
{
inData >> tempWord;
wordMap.insert(pair<string, int>(tempWord, i));
}
search = wordMap.equal_range(keyword);
for (multimap<string, int>::iterator itr = search.first; itr != search.second; ++itr)
{
cout << "The keyword " << keyword << " is found at location " << itr->second << endl;
tempMap = itr;
itr->second = itr->second - 2;
cout << itr->first << endl;
}
Мне известно, что код в цикле for внизу неверен, но это было сделано для целей тестирования.
Вам нужен двунаправленный поиск: вам нужно сопоставить слово с его индексом (вот что wordMap
для) и отдельно вам нужно сопоставить индекс с его словом (это то, что вам не хватает). Итак, давайте добавим это, а также исправим ваш начальный цикл:
std::vector<std::string> words;
while (inData >> tempWord) {
wordMap.insert(std::make_pair(tempWord, words.size()));
words.push_back(tempWord);
}
Теперь у нас это двунаправленно — так как words
позволяет искать по индексу. Таким образом, мы имеем:
for (auto const& pair : as_range(wordMap.equal_range(keyword))) {
for (size_t idx = pair.second - 2; idx < pair.second + 3; ++idx) {
std::cout << words[idx] << ' ';
}
std::cout << '\n';
}
as_range()
это то, что берет пару итераторов и возвращает вам то, что вы можете использовать в выражениях на основе диапазона. Это не учитывает границы words
(если вы выбрали одно из первых двух или двух последних слов в качестве ключевого слова), но это должно поставить вас на правильный путь.
Кроме того, рассмотрите возможность использования std::map<std::string, std::vector<size_t>>
вместо std::multimap<std::string, size_t>
если вы всегда будете перебирать все значения и вам не нужна стабильность итератора. Увидеть этот вопрос для получения дополнительной информации.
Учитывая вашу постановку проблемы, map
не подходит, так как вы сразу теряете всю информацию о местоположении и пытаетесь найти обходной путь. Если вы хотите хранить все свои данные в контейнере, вы можете также хранить их в vector
и выполнить линейный поиск. Да я знаю, это будет теоретически медленнее, но есть все шансы, что на практике это не произойдет …
Для хихиканья, вот совершенно другой подход с <regex>
Услуги:
// Data.
string const text = "Pack my box with five dozen liquor jugs. The quick brown fox jumps over the lazy dog. The five boxing wizards jump quickly.";
// Word to search for.
string target;
cin >> target;
// Capture the target and up to two words before and after.
regex const context(R"((?:([^\s]+)\s)?(?:([^\s]+)\s)?()" + target + R"()(?:\s([^\s]+))?(?:\s([^\s]+))?)");
// Perform search.
smatch matches;
regex_search(text, matches, context);
// Print results.
copy_if(matches.begin() + 1, matches.end(), ostream_iterator<string>(cout, "\n"), mem_fn(&smatch::value_type::matched));