существует ли простой способ сделать это с 2+ словами, такими как Нью-Йорк?
Ответ: Да.
Как отмеченный в ответе @ jackw11111 , ваша проблема с чтением имен, содержащих пробел , была вызвана std::cin
, который читает только с начала строки до первого пробела . Так, например, попытка чтения "New York"
с помощью std::cin >> city;
приведет к city
, содержащему "New"
, тогда как "York"
останется в stdin
непрочитанным.
Решение состоит в том, чтобы использовать getline
, что будет читать до тех пор, пока не будет указан символ-разделитель (по умолчанию: '\n'
).
Теперь, для остальной части вашей проблемы, читая этапы поездки с двумя (или более) городами, разделенными '-'
, есть количество способов, которыми вы можете подойти к проблеме. Поскольку каждый этап поездки будет включать от и до города, использование std :: pair , предоставленного как часть заголовка STL utility
, обеспечит удобный способ хранения связанных из и до городов. Затем вы можете использовать std::vector<std::pair<..,..>>
, чтобы создать вектор пар .
Если вам абсолютно не нужно читать первое целое значение для числа предпринятые поездки - вы можете покончить с этим, так как он действительно не нужен для обработки ввода. На самом деле все, что вам нужно, это ваш home
город, а затем вы можете прочитать столько строк ввода, сколько захотите, и сохранить столько поездок от и до пар города до EOF
при чтении из файла или вводится пустая строка для указания конца ввода.
Для разделения строк читайте с getline
, используя std :: stringstream . Для чтения из std::stringstream
вы можете использовать getline
еще раз (с разделителем '-'
), чтобы отделить города от-до в строке. Помещение строки в поток строк и последующее чтение из потока строк не позволяет getline
пропустить '\n'
, когда разделитель был заменен на что-то другое.
Так что в вашем случае вы можете объявить вектор пар строк, а также несколько дополнительных строк для хранения home
и помощи в разборе, и вы можете просто прочитать сначала город home
, например,
#include <iostream>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
int main (void) {
std::string home, last, trip, total; /* strings */
std::vector<std::pair<std::string, std::string>> vp {}; /* vector of pairs */
std::cout << "enter home city: "; /* prompt for home city */
if (!getline (std::cin, home)) { /* read/validate home city */
std::cerr << "error: failed to read home-city.\n";
return 1;
}
Теперь просто l oop, читая строки ввода и проверка, является ли строка пустой, чтобы указать конец ввода. Создайте поток строк из каждой строки, а затем прочитайте поток строк с помощью getline
(это устраняет необходимость использования substr
для анализа городов из строки). Добавьте каждую пару городов от-до к вашему вектору, используя std :: make_pair :
/* prompt for trips (any number of legs per-line), ENTER alone when done */
std::cout << "\nenter trips (format city1-city2[-cityN]) "
"[Enter] alone when done\n\ntrip: ";
while (getline (std::cin, trip)) { /* while trip entered */
if (!trip.length()) /* if empty (zero length) break */
break;
std::stringstream ss (trip); /* create stringsteam from line */
std::string from, to; /* strings for from and to cities */
if (getline (ss, from, '-')) { /* get from city from stringstrem */
while (getline (ss, to, '-')) { /* get to city from stringstream */
vp.push_back(std::make_pair (from, to)); /* add pair to vector */
from = to; /* update from = to */
}
}
std::cout << "trip: "; /* prompt for next trip */
}
Наконец, просто l oop над сохраненными парами ( с вложенными циклами), чтобы выбрать все этапы отключения на основе от-до , а затем найти следующее, установив from = to;
и найдя следующее совпадение. (вы также можете добавить дополнительные проверки, чтобы убедиться, что на каждой итерации найдены правильные значения от-до - что вам остается - что-то простое, как bool found;
сделает)
total = home; /* initialize total & last to home */
last = home;
for (auto t1 : vp) { /* loop over each trip */
for (auto t2 : vp) { /* 2nd search loop */
if (t2.first == last) { /* find trip begins with last city */
total += "-" + t2.second; /* add trip end to total */
last = t2.second; /* update last to end */
break; /* go find next trip */
}
}
}
std::cout << '\n' << total << '\n'; /* output total trip beg to end */
( примечание: первый объект в каждом std::pair
доступен с помощью .first
, а второй с помощью .second
- даже несколько логично ...)
Там Есть много вариантов, которые вы можете придумать. В целом, вы можете сделать:
#include <iostream>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
int main (void) {
std::string home, last, trip, total; /* strings */
std::vector<std::pair<std::string, std::string>> vp {}; /* vector of pairs */
std::cout << "enter home city: "; /* prompt for home city */
if (!getline (std::cin, home)) { /* read/validate home city */
std::cerr << "error: failed to read home-city.\n";
return 1;
}
/* prompt for trips (any number of legs per-line), ENTER alone when done */
std::cout << "\nenter trips (format city1-city2[-cityN]) "
"[Enter] alone when done\n\ntrip: ";
while (getline (std::cin, trip)) { /* while trip entered */
if (!trip.length()) /* if empty (zero length) break */
break;
std::stringstream ss (trip); /* create stringsteam from line */
std::string from, to; /* strings for from and to cities */
if (getline (ss, from, '-')) { /* get from city from stringstrem */
while (getline (ss, to, '-')) { /* get to city from stringstream */
vp.push_back(std::make_pair (from, to)); /* add pair to vector */
from = to; /* update from = to */
}
}
std::cout << "trip: "; /* prompt for next trip */
}
total = home; /* initialize total & last to home */
last = home;
for (auto t1 : vp) { /* loop over each trip */
for (auto t2 : vp) { /* 2nd search loop */
if (t2.first == last) { /* find trip begins with last city */
total += "-" + t2.second; /* add trip end to total */
last = t2.second; /* update last to end */
break; /* go find next trip */
}
}
}
std::cout << '\n' << total << '\n'; /* output total trip beg to end */
}
Пример использования / Вывод
$ ./bin/triptotal
enter home city: Paris
enter trips (format city1-city2[-cityN]) [Enter] alone when done
trip: Berlin-Paris
trip: Paris-New York
trip: New York-Zagreb
trip: Ljubljana-Berlin
trip: Zagreb-Ljubljana
trip:
Paris-New York-Zagreb-Ljubljana-Berlin-Paris
Это также можно ввести как:
$ ./bin/triptotal
enter home city: Paris
enter trips (format city1-city2[-cityN]) [Enter] alone when done
trip: San Antonio-New York-Berlin-Paris
trip: Paris-Frankfort-Zagreb
trip: Zagreb-Ljubljana-Dallas
trip: Dallas-San Antonio
trip:
Paris-Frankfort-Zagreb-Ljubljana-Dallas-San Antonio-New York-Berlin-Paris
Еще одна ваша задача - найти способ справиться с несколькими этапами поездки, которые могут посетить один и тот же город. (это тоже оставлено для вас) Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.