Как использовать getline и stringstream для анализа форматированного ввода даты и времени?

Я работаю на c++ всего около месяца. Я не очень понимаю, как это работает, однако мне нужно написать программу для школы. Я использовал функцию void, и, похоже, она работает до сих пор, но я понятия не имею, что делать дальше. Я потерялся в строке 44, я не уверен, как заставить ее работать, есть ли способ получить значение из определенная строка? Если значение находится в обеих строках, как мне определить, какое значение? Вот мое задание:

Гараж взимает минимальную плату в размере 2 долларов США за парковку на срок до трех часов. Гараж взимает дополнительную плату в размере 0,50 доллара США в час за каждый час или его часть сверх трех часов. Максимальная плата за любой заданный 24-часовой период составляет 10 долларов США. Люди, которые паркуют свои машины более 24 часов, будут платить 8 долларов в день.

Напишите программу, которая вычисляет и печатает плату за парковку. Входными данными для вашей программы являются дата и время, когда автомобиль въезжает в гараж, а также дата и время, когда тот же автомобиль покидает гараж. Оба входа имеют формат ГГ/ММ/ДД чч:мм.

Вот код, который я написал до сих пор:

#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <cmath>
#include <algorithm>
#include <sstream>
using namespace std;

stringstream ss;
string enter_date;
string enter_time;
string exit_date;
string exit_time;
int calculatecharge;
int num;
int i;
int year;
int month;
int ddmmyyChar;
int dayStr;
string line;
int x;

void atk() 
{
    getline (cin,line);             // This is the line entered by the user
    stringstream  ss1(line);        // Use stringstream  to interpret that line
    ss >> enter_date >> enter_time;
    stringstream  ss2(enter_date);  // Use stringstream  to interpret date
    string year, month, day;
    getline (ss2, year, '/');
}

int main()
{
    cout << "Please enter the date and time the car is entering "<< endl
         << "the parking garage in the following format: YY/MM/DD hh:mm"<< endl;
    atk();
    cout << "Please enter the date and time the car is exiting "<< endl
         << "the parking garage in the following format: YY/MM/DD hh:mm"<< endl;
    atk();
    if (hr - hr < 3)
        cout<<"Parking fee due: $2.00" << endl;

person user1311854    schedule 06.04.2012    source источник
comment
Некоторые из файлов заголовков, которые вы включили, не нужны. Например, если вы не выполняете файловый ввод-вывод, вам не нужен #include <fstream>.   -  person bwDraco    schedule 17.09.2012


Ответы (3)


Напишите программу, которая вычисляет и печатает плату за парковку.

Это цель нашей программы. В общем, это выход.

Входными данными для вашей программы являются дата и время, когда автомобиль въезжает в гараж, а также дата и время, когда тот же автомобиль покидает гараж. Оба входа имеют формат ГГ/ММ/ДД чч:мм.

Итак, нам нужен какой-то способ перевода формата даты, введенного в виде строки, во время разницу. Вы можете сохранить время в int, которое представляет количество минут, прошедших в течение периода парковки (я выбираю минуты, так как это наименьший введенный период времени). Задача здесь состоит в том, чтобы преобразовать строку в это целое число.

Вы можете написать такую ​​функцию:

int parseDate( std::string dateStr )
{
    // Format: YY/MM/DD hh:mm
    int year  = atoi( dateStr.substr( 0, 2 ).c_str() );
    int month = atoi( dateStr.substr( 3, 2 ).c_str() );
    int day   = atoi( dateStr.substr( 6, 2 ).c_str() );
    int hour  = atoi( dateStr.substr( 9, 2 ).c_str() );
    int min   = atoi( dateStr.substr( 12, 2 ).c_str() );

    // Now calculate no. of mins and return this
    int totalMins = 0;
    totalMins += ( year * 365 * 24 * 60 ); // Warning: may not be accurate enough
    totalMins += ( month * 30 * 24 * 60 ); // in terms of leap years and the fact
    totalMins += ( day * 24 * 60 );        // that some months have 31 days
    totalMins += ( hour * 60 );
    totalMins += ( min );

    return totalMins;
}

Осторожный! Моя функция здесь просто иллюстрация, и она не принимает во внимание такие тонкости, как високосные годы и разная длина месяца. Вероятно, вам нужно будет улучшить его. Важно понимать, что он пытается взять строку и вернуть количество минут, прошедших с '00 года. Это означает, что нам просто нужно вычесть два целых числа из двух строк даты, чтобы найти прошедшее время:

int startTime = parseDate( startDateString );
int endTime   = parseDate( endDateString );
int elapsedTime = endTime - startTime; // elapsedTime is no. of minutes parked

Это, вероятно, самая сложная часть проблемы, как только вы решите это, остальное должно быть более простым. Я дам вам еще несколько советов:

Гараж взимает минимальную плату в размере 2 долларов США за парковку на срок до трех часов.

По сути, просто фиксированная ставка: несмотря ни на что, выходная переменная, описывающая стоимость, должна быть равна как минимум 2.00.

Гараж взимает дополнительную плату в размере 0,50 доллара США в час за каждый час или его часть сверх трех часов.

Определите количество часов, прошедших за последние три часа, — вычтите 180 из elapsedTime. Если это больше, чем 0, разделите его на 60 и сохраните результат в float (поскольку это не обязательно целочисленный результат), скажем, excessHours. Используйте excessHours = floor( excessHours ) + 1;, чтобы округлить это число в большую сторону. Теперь умножьте это на 0.5; это дополнительные расходы. (Попытайтесь понять, почему это работает математически).

Максимальная плата за любой заданный 24-часовой период составляет 10 долларов США. Люди, которые паркуют свои машины более 24 часов, будут платить 8 долларов в день.

Я оставлю это на ваше усмотрение, так как это, в конце концов, домашнее задание. Надеюсь, я предоставил достаточно, чтобы вы поняли суть того, что нужно сделать. Есть много возможных подходов к этой проблеме, это всего лишь один, и он может быть или не быть «лучшим».

person Alex Z    schedule 06.04.2012
comment
Большое спасибо за помощь! Я не был уверен в математике, но то, как вы это объяснили, имеет большой смысл. Я очень ценю это. - person user1311854; 06.04.2012
comment
Здравствуйте, я очень ценю всю помощь, которую вы мне оказали, но я все еще полностью потерян. Я понятия не имею, что делать или даже то, что вы сделали точно. после того, как вы поместите строку в правильный формат, как мне это использовать и как использовать вычисления? - person user1311854; 07.04.2012
comment
После преобразования строк даты в целые числа эти целые числа теперь представляют количество минут, прошедших с '00 года. Вычитая «начальное» время из «конечного» времени, вы получаете разницу во времени между въездом и выездом с парковки в минутах. Это позволяет рассчитать комиссию. Это то, о чем ты говоришь? - person Alex Z; 07.04.2012
comment
Да, однако у меня возникли проблемы с тем, чтобы эта часть работала. Я не знаю, как исправить ошибку C2371: 'std::cin' : redefinition; различные основные виды. - person user1311854; 07.04.2012
comment
Трудно помочь без кода, но есть много ресурсов в Интернете, которые ссылаются на эту ошибку. Я бы посоветовал провести тщательный поиск в Google, и если это ничего не даст, вы можете задать другой вопрос. Комментарии — не лучшее место для диагностики/исправления ошибок в коде. - person Alex Z; 08.04.2012
comment
Я уже задавал другой вопрос, в заголовке используется atoi и ошибка: неразрешенный внешний символ. Я был бы очень признателен, если бы вы могли просмотреть его для меня. - person user1311854; 08.04.2012
comment
Совет, данный вам в этом вопросе, кажется правильным.. функция должна быть определена за пределами main(), но ее можно вызвать в пределах main()... - person Alex Z; 08.04.2012

Прежде всего, поскольку и строка для даты, и строка для времени являются непрерывными (не содержат пробелов), вам не нужно использовать stringstream для синтаксического анализа строки. Вы можете прочитать дату и время так:

cin >> enter_date >> enter_time;
cin >> exit_date >> exit_time;

Теперь вам нужно преобразовать эти строки в фактические даты и время. Поскольку формат обоих фиксирован, вы можете написать что-то вроде этого:

void parse_date(const string& date_string, int& y, int& m, int& d) {
  y = (date_string[0] - '0')*10 + date_string[1] - '0'; // YY/../..
  m = (date_string[3] - '0')*10 + date_string[4] - '0'; // ../mm/..
  d = (date_string[6] - '0')*10 + date_string[7] - '0'; // ../../dd
}

Конечно, этот код несколько уродлив и может быть написан лучше, но я считаю, что так его легче понять. Имея эту функцию, должно быть очевидно, как ее написать:

void parse_time(const string& time_string, int& h, int &m);

Теперь, когда вы проанализировали дату и время, вам нужно реализовать метод, который вычитает две даты. На самом деле вас волнует количество часов, прошедших с даты ввода до даты выхода, округленное в большую сторону. Я предлагаю здесь преобразовать даты в количество дней с некоторого начального момента (скажем, 01.01.01), а затем вычесть два значения. Затем преобразуйте оба времени в количество минут с 00:00 и снова вычтите их. Это не зависит от языка, поэтому я считаю, что этих советов должно быть достаточно. Опять же, используя некоторые встроенные библиотеки, это можно сделать проще, но я не думаю, что это идея вашего задания.

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

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

person Ivaylo Strandjev    schedule 06.04.2012
comment
Большое спасибо! Я работал над этим в течение нескольких дней, и вы первый человек, который объяснил это достаточно, чтобы я понял. Я очень ценю это. - person user1311854; 06.04.2012
comment
Это имеет гораздо больше смысла, мой инструктор сказал мне, что использование cin не сработает, что мне пришлось использовать getline, что сбило меня с толку, спасибо за разъяснение. - person user1311854; 06.04.2012

Вам не нужно выполнять отдельные операции чтения и синтаксического анализа ввода. Вы можете передать необходимые переменные по ссылке и прочитать ввод непосредственно в переменные, используя stringstream. Я бы использовал структуру для хранения даты и времени и перегрузил бы operator- алгоритмом вычитания двух значений даты/времени. Вот как бы я это сделал:

#include <iostream>
#include <sstream>

using namespace std;

struct DateTime {
    // Variables for each part of the date and time
    int year, month, day, hour, minute;

    // Naive date and time subtraction algorithm
    int operator-(const DateTime& rval) const {
        // Total minutes for left side of operator
        int lvalMinutes = 525600 * year
                        + 43200 * month
                        + 1440 * day
                        + 60 * hour
                        + minute;

        // Total minutes for right side of operator
        int rvalMinutes = 525600 * rval.year
                        + 43200 * rval.month
                        + 1440 * rval.day
                        + 60 * rval.hour
                        + rval.minute;

        // Subtract the total minutes to determine the difference between
        // the two DateTime's and return the result.
        return lvalMinutes - rvalMinutes;
    }
};

bool inputDateTime(DateTime& dt) {
    // A string used to store user input.
    string line;
    // A dummy variable for handling separator characters like "/" and ":".
    char dummy;

    // Read the user's input.
    getline(cin, line);
    stringstream lineStream(line);

    // Parse the input and store each value into the correct variables.
    lineStream >> dt.year >> dummy >> dt.month >> dummy >> dt.day >> dummy 
               >> dt.hour >> dummy >> dt.minute;

    // If input was invalid, print an error and return false to signal failure
    // to the caller.  Otherwise, return true to indicate success.
    if(!lineStream) {
        cerr << "You entered an invalid date/time value." << endl;
        return false;
    } else
        return true;
}

Отсюда в функции main() объявите две структуры DateTime, одну для времени входа и одну для времени выхода. Затем прочитайте обе DateTime, вычтите время входа из времени выхода и используйте результат для создания правильного вывода.

person bwDraco    schedule 17.09.2012