Хороший синтаксический сахар, который вы добавили!

грушки в колиру, который я использую для тестирования:http://coliru.stacked-crooked.com/a/4039865d8d4dad52

После долгого перерыва я снова привыкаю к ​​C ++. Я пишу код, который анализирует CSV, который может иметь несколько столбцов с датами или нулями. Я предполагаю, что каждый столбец даты имеет ровно один вид допустимого формата даты, хотя разные столбцы могут иметь разные форматы.

Для каждого столбца даты, который у меня есть, я нахожу первое значение, которое успешно анализируется как дата, заданная std :: vector потенциальных локалей с объектом boost date_input_facet. Эта первая дата, которая правильно анализирует, вернет индекс в моем массиве локалей, который работал. Как только у меня будет подходящий формат для первой анализируемой даты, я хочу навсегда исправить этот формат, чтобы мне больше не приходилось тратить время процессора на его определение.

Вот мой массив локалей:

const std::vector<std::locale> Date::date_formats = {
    std::locale(std::locale::classic(), new date_input_facet("%Y-%m-%d")),
    std::locale(std::locale::classic(), new date_input_facet("%Y/%m/%d")),
    std::locale(std::locale::classic(), new date_input_facet("%m-%d-%Y")),
    std::locale(std::locale::classic(), new date_input_facet("%m/%d/%Y")),
    std::locale(std::locale::classic(), new date_input_facet("%d-%b-%Y")),
    std::locale(std::locale::classic(), new date_input_facet("%Y%m%d")),
};

Я использую массив строк дат с 20170101 по 20170131, чтобы проверить это. Затем я распечатываю исходные строки даты, проанализированную дату, а также индекс вектора date_formats, который работал для анализа.

В период с 20170101 по 201700129 написано, что сработал 0-й индекс, который должен иметь формат «% Y-% m-% d» с тире?!?! Более того, там, где идут тире, у меня есть числа, поэтому они читают 20170101 как 2017-10 - затем отбрасываем последний тире и интерпретируем его как октябрь 2017 года, который без даты - 1 октября 2017 года. Зачем это делать, если это не так? формат, который он должен был использовать?

Некоторые результаты, которые можно увидеть из моей колиры (pY - год анализа и т. Д.):

YYYYMMDD    pY     pM   pD  format_index
20170101    2017    Oct 1   0
20170102    2017    Oct 1   0
20170103    2017    Oct 1   0
20170104    2017    Oct 1   0
20170105    2017    Oct 1   0

Для 20170130, 20170131 правильный индекс формата (5-й) сообщается для «% Y% m% d».

Есть идеи? Я хочу использовать только точную строку формата, которую я передал.

Ответы на вопрос(2)

Решение Вопроса

оже было трудно / невозможно добиться строгого разбора с использованием средств стандартной библиотеки и boost.

Я в конечном итоге с помощьюstrptime - в основном…

adaptive_parser

Предназначен для заполнения списком поддерживаемых форматов в порядке предпочтения. По умолчанию парсер не адаптивный (режимfixed).

В адаптивных режимах формат может потребоваться

sticky (последовательно использовать первый подобранный формат)ban_failed (удалить ошибочные шаблоны из списка; запрет происходит только при успешном разборе, чтобы избежать запрета всех шаблонов при неверном вводе)mru (сохраняет список, но переупорядочивает для выполнения)

Внимание:
Если форматы неоднозначны (например,mm-dd-yyyy противdd-mm-yyyy) разрешить переупорядочение результатов в непредсказуемые результаты.

⇒ Используйте толькоmru когда нет двусмысленных форматов

НОТА:
Объект функции с состоянием. В алгоритмах передайте его по ссылке (std::ref(obj)) избегать копирования шаблонов и обеспечения правильного адаптивного поведения

демонстрация

Я попробовал парсер на ваших тестовых данных:

#include "adaptive_parser.h"
#include <boost/date_time/gregorian/greg_date.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

class Date{
public:
    Date() : y(0), m(0), d(0) {}
    Date(int yy, int mm, int dd) : y(yy), m(mm), d(dd) {}
    Date(boost::gregorian::date dt) : y(dt.year()), m(dt.month()), d(dt.day()) {}
    Date(std::string const& delimitedString);

    std::string to_string() const;

    int getYear()  const { return y; }
    int getMonth() const { return m; }
    int getDay()   const { return d; }
 private:
    using parser_t = mylib::datetime::adaptive_parser;
    parser_t parser { parser_t::full_match, 
        {
            "%Y-%m-%d", "%Y/%m/%d",
            "%m-%d-%Y", "%m/%d/%Y",
            "%d-%b-%Y",
            "%Y%m%d",
        } };

    int y, m, d;
};

Date::Date(const std::string& delimitedString)
{
    using namespace boost::posix_time;

    auto t = ptime({1970,1,1}) + seconds(parser(delimitedString).count());

    *this = Date(t.date());
}

std::string Date::to_string() const
{
    std::ostringstream os;

    os << std::setfill('0')
       << std::setw(4) << y 
       << std::setw(2) << m 
       << std::setw(2) << d;

    return os.str();
}

int main() {
    std::vector<Date> vec(31);
    std::generate(vec.begin(), vec.end(), [i=1]() mutable { return Date(2017,1,i++); });

    std::vector<std::string> strvec;
    std::transform(vec.begin(), vec.end(), back_inserter(strvec), std::mem_fn(&Date::to_string));

    std::cout << "YYYYMMDD\tpY\tpM\tpD\tformat_index\n";

    for (auto& str : strvec) {
        Date parsed(str);

        std::cout << str 
            << "\t" << parsed.getYear()
            << "\t" << parsed.getMonth()
            << "\t" << parsed.getDay()
            << "\t" << "?"
            << "\n";
    }
}

Печать:

YYYYMMDD    pY  pM  pD  format_index
20170101    2017    1   1   ?
20170102    2017    1   2   ?
20170103    2017    1   3   ?
20170104    2017    1   4   ?
20170105    2017    1   5   ?
20170106    2017    1   6   ?
20170107    2017    1   7   ?
20170108    2017    1   8   ?
20170109    2017    1   9   ?
20170110    2017    1   10  ?
20170111    2017    1   11  ?
20170112    2017    1   12  ?
20170113    2017    1   13  ?
20170114    2017    1   14  ?
20170115    2017    1   15  ?
20170116    2017    1   16  ?
20170117    2017    1   17  ?
20170118    2017    1   18  ?
20170119    2017    1   19  ?
20170120    2017    1   20  ?
20170121    2017    1   21  ?
20170122    2017    1   22  ?
20170123    2017    1   23  ?
20170124    2017    1   24  ?
20170125    2017    1   25  ?
20170126    2017    1   26  ?
20170127    2017    1   27  ?
20170128    2017    1   28  ?
20170129    2017    1   29  ?
20170130    2017    1   30  ?
20170131    2017    1   31  ?

Stuff только вещи часового пояса нуждаются в настройках, в основном

 FinanceGuyThatCantCode29 сент. 2017 г., 20:13
Очень хорошо ... так что я думаю, что вы столкнулись с тем же не интуитивным материалом, что и я - ребята из std / boost действительно должны это исправить! Я также ценю гибкость вашей адаптивности - это именно то, что я пытаюсь сделать. Предполагая, что это работает (я уверен, что это делает), это выглядит великолепно.
 sehe29 сент. 2017 г., 22:28
Число рейнольдса Входные аспекты Boost: Трудно понять, что является ошибкой, а что нет, из-за недостаточно определенных контрактов. Но да, это непригодно в моей книге

С помощьюБесплатная библиотека Говарда Хиннанта с открытым исходным кодом C ++ 11/14/17, дата / время, это:

#include "date/date.h"
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

int
localeIndexFromString(const std::string& delimitedString)
{
    using namespace std;
    static vector<string> date_formats
    {
        "%Y-%m-%d",
        "%Y/%m/%d",
        "%m-%d-%Y",
        "%m/%d/%Y",
        "%d-%b-%Y",
        "%Y%m%d"
    };

    istringstream is;
    date::year_month_day dt;
    size_t i;
    for (i = 0; i < date_formats.size(); ++i)
    {
        is.clear();
        is.str(delimitedString);
        is >> date::parse(date_formats[i], dt);
        if (!is.fail())
        {
            std::cout << dt.year() << "\t" << dt.month() << "\t" << dt.day();
            return i;
        }
    }
    return -1;
}

int
main()
{
    using namespace date::literals;
    std::vector<date::year_month_day> vec;
    for (auto i = 1; i < 32; ++i)
        vec.push_back(2017_y/jan/i);

    std::vector<std::string> strvec;
    for (auto const& d : vec)
        strvec.push_back(date::format("%Y%m%d", d));

    std::cout << "YYYYMMDD\tpY\tpM\tpD\tformat_index\n";

    for (size_t i=0; i < strvec.size(); ++i)
    {
        std::cout << strvec[i] << "\t";
        int fmt_index = localeIndexFromString(strvec[i]);
        std::cout << "\t" << fmt_index << "\n";
    }
}

Выходы:

YYYYMMDD        pY        pM        pD        format_index
20170101        2017      Jan       01        5
20170102        2017      Jan       02        5
20170103        2017      Jan       03        5
20170104        2017      Jan       04        5
20170105        2017      Jan       05        5
20170106        2017      Jan       06        5
20170107        2017      Jan       07        5
20170108        2017      Jan       08        5
20170109        2017      Jan       09        5
20170110        2017      Jan       10        5
20170111        2017      Jan       11        5
20170112        2017      Jan       12        5
20170113        2017      Jan       13        5
20170114        2017      Jan       14        5
20170115        2017      Jan       15        5
20170116        2017      Jan       16        5
20170117        2017      Jan       17        5
20170118        2017      Jan       18        5
20170119        2017      Jan       19        5
20170120        2017      Jan       20        5
20170121        2017      Jan       21        5
20170122        2017      Jan       22        5
20170123        2017      Jan       23        5
20170124        2017      Jan       24        5
20170125        2017      Jan       25        5
20170126        2017      Jan       26        5
20170127        2017      Jan       27        5
20170128        2017      Jan       28        5
20170129        2017      Jan       29        5
20170130        2017      Jan       30        5
20170131        2017      Jan       31        5
 FinanceGuyThatCantCode29 сент. 2017 г., 20:00
Никаких объяснений, но я ценю работу, которую вы сделали по предоставленной вами ссылке! Я прочитаю это более подробно позже.
 FinanceGuyThatCantCode29 сент. 2017 г., 20:10
Хороший синтаксический сахар, который вы добавили!

Ваш ответ на вопрос