Доступ к элементам в мультикарте

Я пытаюсь создать программу, которая принимает данные из .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 внизу неверен, но это было сделано для целей тестирования.

2

Решение

Вам нужен двунаправленный поиск: вам нужно сопоставить слово с его индексом (вот что 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> если вы всегда будете перебирать все значения и вам не нужна стабильность итератора. Увидеть этот вопрос для получения дополнительной информации.

0

Другие решения

Учитывая вашу постановку проблемы, 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));
0

По вопросам рекламы [email protected]