2013-10-20 41 views
6

我正在研究一個項目,我必須閱讀一個日期以確保它是一個有效的日期。例如,2月29日只是閏年的有效日期,或者6月31日不是有效日期,因此計算機會根據輸入信息輸出該信息。我的問題是,我無法弄清楚如何解析字符串,以便用戶可以輸入「05/11/1996」作爲日期(例如),然後將其放入單獨的整數中。我正在考慮嘗試使用while循環和字符串流做些事情,但我有點卡住了。如果有人能幫助我,我會很感激。如何在C++中解析和驗證std :: string中的日期?

回答

5

如果格式就像你的榜樣,你可以取出整數這樣的:

int day, month, year; 
sscanf(buffer, "%2d/%2d/%4d", 
    &month, 
    &day, 
    &year); 

其中當然在緩衝區你有日期(「1996年5月11日」)

+0

有沒有一種方法可以使用字符串?我把它放到一些代碼中,並將一個變量緩衝區設置爲「05/20/13」,不幸的是它說在string和const char之間沒有合適的轉換。 – emufossum13

+0

是的,如果你使用std :: string,那麼buffer.c_str()就是你需要的。 – DrM

+0

這是我如何設置變量decleration std :: string buffer = buffer。c_str(); buffer =「05/10/1996」; 是你在說什麼? – emufossum13

11

一個可能的解決方案也是基於strptime,但是請注意,此功能僅驗證日是否爲從區間<1;31>和一個月<1;12>,即"30/02/2013"是有效的還是:

#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; 
} 
但由於 strptime並不總是可用的和額外的驗證將是很好,這裏是你能做什麼:
  1. 提取日,月,年
  2. 填寫struct tm
  3. 正常化它
  4. 檢查是否歸日期仍然與檢索日期,月份,年份相同

ie:

#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; 
} 

用作:

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; 
} 

在這種情況下將輸出date is invalid因爲正常化將檢測29/02/2013已被標準化爲01/03/2013

+0

很好的答案。當Google試圖找到驗證輸入日期的方法時,Google搜索將我帶到了這裏。您的方法還處理閏年和其他邊緣情況,這非常棒。 – DaV

+0

有一個問題:如果你輸入的年份低於1970年(epoch年),它將被歸一化到1970年,並且該函數將失敗 –

5

我寧願使用升壓日期時間:

看到它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"; 
    } 
} 

輸出:

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 
+0

我剛剛重構了我的答案以顯示(a)如何有效地重新使用imbued流解析(b)它驗證輸入 – sehe

3

另一種選擇是使用std::get_time<iomanip>頭(可自C++ 11以來)。它的一個很好的例子可以找到here