Sto lavorando a un progetto in cui devo leggere una data per assicurarmi che sia una data valida. Ad esempio, il 29 febbraio è solo una data valida negli anni bisestili o il 31 giugno non è una data valida, quindi il computer produrrebbe tali informazioni in base all'input. Il mio problema è che non riesco a capire come analizzare la stringa in modo che l'utente possa inserire "05/11/1996" come una data (ad esempio) e quindi prenderlo e inserirlo in numeri interi separati. Stavo pensando di provare a fare qualcosa con un ciclo while e un flusso di stringhe, ma sono un po 'bloccato. Se qualcuno potesse aiutarmi con questo, lo apprezzerei davvero.Come analizzare e convalidare una data in std :: string in C++?
risposta
Se il formato è come nel tuo esempio, si potrebbe prendere l'intero in questo modo:
int day, month, year;
sscanf(buffer, "%2d/%2d/%4d",
&month,
&day,
&year);
in cui, naturalmente, in un tampone si ha la data ("1996/05/11")
Una possibile soluzione potrebbe essere basata anche su strptime
, tuttavia notare che questa funzione convalida solo se il giorno è dall'intervallo <1;31>
e mese dalla <1;12>
, cioè "30/02/2013"
vale ancora:
#include <iostream>
#include <ctime>
int main() {
struct tm tm;
std::string s("32/02/2013");
if (strptime(s.c_str(), "%d/%m/%Y", &tm))
std::cout << "date is valid" << std::endl;
else
std::cout << "date is invalid" << std::endl;
}
Ma poiché
strptime
non è sempre disponibile e un'ulteriore convalida sarebbe bello, ecco cosa si potrebbe fare:
- estratto giorno, mese, anno
- riempire
struct tm
- normalizzarlo
- verifica se la data normalizzata è ancora lo stesso giorno recuperate, mese, anno
cioè:
#include <iostream>
#include <sstream>
#include <ctime>
// function expects the string in format dd/mm/yyyy:
bool extractDate(const std::string& s, int& d, int& m, int& y){
std::istringstream is(s);
char delimiter;
if (is >> d >> delimiter >> m >> delimiter >> y) {
struct tm t = {0};
t.tm_mday = d;
t.tm_mon = m - 1;
t.tm_year = y - 1900;
t.tm_isdst = -1;
// normalize:
time_t when = mktime(&t);
const struct tm *norm = localtime(&when);
// the actual date would be:
// m = norm->tm_mon + 1;
// d = norm->tm_mday;
// y = norm->tm_year;
// e.g. 29/02/2013 would become 01/03/2013
// validate (is the normalized date still the same?):
return (norm->tm_mday == d &&
norm->tm_mon == m - 1 &&
norm->tm_year == y - 1900);
}
return false;
}
utilizzati come:
int main() {
std::string s("29/02/2013");
int d,m,y;
if (extractDate(s, d, m, y))
std::cout << "date "
<< d << "/" << m << "/" << y
<< " is valid" << std::endl;
else
std::cout << "date is invalid" << std::endl;
}
che in questo caso sarebbe uscita dal date is invalid
normalizzazione rileverebbe che 29/02/2013
è stata normalizzata per 01/03/2013
.
bella risposta. La ricerca su Google mi ha portato qui quando cercavo di trovare un modo per convalidare una data inserita in C. Il tuo metodo gestisce anche gli anni bisestili e altri casi limite che sono grandiosi. – DaV
C'è un problema: se si immette un anno inferiore al 1970 (epoca epoca), verrà normalizzato fino al 1970 e la funzione non riuscirà –
preferisco usare Boost DateTime:
vederlo Live on Coliru
#include <iostream>
#include <boost/date_time/local_time/local_time.hpp>
struct dateparser
{
dateparser(std::string fmt)
{
// set format
using namespace boost::local_time;
local_time_input_facet* input_facet = new local_time_input_facet();
input_facet->format(fmt.c_str());
ss.imbue(std::locale(ss.getloc(), input_facet));
}
bool operator()(std::string const& text)
{
ss.clear();
ss.str(text);
bool ok = ss >> pt;
if (ok)
{
auto tm = to_tm(pt);
year = tm.tm_year;
month = tm.tm_mon + 1; // for 1-based (1:jan, .. 12:dec)
day = tm.tm_mday;
}
return ok;
}
boost::posix_time::ptime pt;
unsigned year, month, day;
private:
std::stringstream ss;
};
int main(){
dateparser parser("%d/%m/%Y"); // not thread safe
// parse
for (auto&& txt : { "05/11/1996", "30/02/1983", "29/02/2000", "29/02/2001" })
{
if (parser(txt))
std::cout << txt << " -> " << parser.pt << " is the "
<< parser.day << "th of "
<< std::setw(2) << std::setfill('0') << parser.month
<< " in the year " << parser.year << "\n";
else
std::cout << txt << " is not a valid date\n";
}
}
Uscite:
05/11/1996 -> 1996-Nov-05 00:00:00 is the 5th of 11 in the year 96
30/02/1983 is not a valid date
29/02/2000 -> 2000-Feb-29 00:00:00 is the 29th of 02 in the year 100
29/02/2001 is not a valid date
Ho appena refactored la mia risposta per mostrare (a) come riutilizzare in modo efficiente il flusso imbastito per parsing (b) che convalida gli input – sehe
Un'altra opzione è quella di utilizzare std::get_time
dalla testata <iomanip>
(disponibile dal C++ 11). Un buon esempio del suo utilizzo può essere trovato here.
- 1. Cython C++ e std :: string
- 2. Come convalidare una data MySQL in PHP?
- 3. Converti float in std :: string in C++
- 4. analizzare una data in rotaie
- 5. Differenza tra std: string e std :: string
- 6. flusso std :: string analizzare un numero in formato binario
- 7. Come trasformare System :: String^in std :: string?
- 8. Espressione regolare C# per convalidare una data?
- 9. Ottieni byte da std :: string in C++
- 10. Come posso assumere la proprietà di un C++ std :: string char data senza copiare e mantenere l'oggetto std :: string?
- 11. Emissione di data e ora in C++ utilizzando std :: chrono
- 12. Usando sprintf con std :: string in C++
- 13. C++ .NET converti System :: String in std :: string
- 14. Come convertire il char unsigned * in std :: string in C++?
- 15. Parse Data string in Ruby
- 16. std :: string :: find non funziona come previsto in C++
- 17. C++ std :: string su booleano
- 18. Come convalidare una data nei binari?
- 19. SWIG: come avvolgere std :: string & (std :: string passato per riferimento)
- 20. std :: string :: c_str() e provvisori
- 21. convertire std :: string in basic_ostream?
- 22. C++ std :: string a jstring con una lunghezza fissa
- 23. Come convertire std :: string in LPCSTR?
- 24. come leggere i file di immagine e memorizzarli in memoria (std :: string) in C++?
- 25. Come convertire std :: string in const char *?
- 26. C++ - std :: wstring a std :: string - conversione rapida e sporca da utilizzare come chiave in std :: map
- 27. Come convertire String in data e ora in Scala?
- 28. YYYYMMDD Formato data Espressione regolare per convalidare una data in C# .net
- 29. Come convertire std :: string in NSString?
- 30. Come convertire QString in std :: string?
c'è un modo che questo possa funzionare con una stringa? Metto questo in un codice e impostando un buffer variabile come "05/20/13", sfortunatamente sta dicendo che non esiste una conversione adeguata tra string e const char. – emufossum13
Sì, se si utilizza una std :: string, di buffer.c_str() è ciò che vi serve. – DrM
Ecco come ho impostato la decodifica variabile std :: string buffer = buffer.c_str(); buffer = "05/10/1996"; è quello di cui stai parlando? – emufossum13