C++ C++;boost date\u input\u facet似乎意外地解析了传递给facet构造函数的格式不正确的日期
我用于测试的coliru中的玩具代码: 我在使用C++之后又重新习惯了。我正在编写代码,解析可能有多个带有日期或空值的列的CSV。我的假设是,每个日期列都有一种有效的日期格式,尽管不同的列可能有不同的格式 对于我拥有的每个日期列,我都会找到第一个值,该值被成功解析为一个日期,给定了一个包含boost date\u input\u facet对象的潜在地区的std::vector。正确解析的第一个日期将返回我所在的区域设置数组中的索引。一旦我有了第一个可解析日期的合适格式,我想永远修复该格式,这样我就不必再浪费CPU时间来检测该格式 以下是我的区域设置数组:C++ C++;boost date\u input\u facet似乎意外地解析了传递给facet构造函数的格式不正确的日期,c++,date,parsing,boost,C++,Date,Parsing,Boost,我用于测试的coliru中的玩具代码: 我在使用C++之后又重新习惯了。我正在编写代码,解析可能有多个带有日期或空值的列的CSV。我的假设是,每个日期列都有一种有效的日期格式,尽管不同的列可能有不同的格式 对于我拥有的每个日期列,我都会找到第一个值,该值被成功解析为一个日期,给定了一个包含boost date\u input\u facet对象的潜在地区的std::vector。正确解析的第一个日期将返回我所在的区域设置数组中的索引。一旦我有了第一个可解析日期的合适格式,我想永远修复该格式,这
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")),
};
对于20170130、20170131,报告了“%Y%m%d”的正确格式索引(第5个)
有什么想法吗?我只希望使用我传递的精确格式字符串。我自己制作了一个支持多种格式的日期-时间解析器。一、 同样,他们发现使用标准库和boost中的工具很难/不可能严格解析 我最终使用了
strtime
——大部分是\
计划以支持的格式列表为种子,顺序为
偏爱默认情况下,解析器是不自适应的(模式是固定的
)
在自适应模式下,可以要求
(始终重复使用第一个匹配的格式)sticky
(从列表中删除失败的模式;仅发生禁止 成功解析以避免禁止无效输入上的所有模式)ban_failed
(保留列表,但为性能重新排序)mru
- 注意:
如果格式不明确(例如,
vsmm-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";
}
}
只是时区的东西需要调整,主要是我自己做了一个多格式的日期时间解析器。一、 同样,他们发现使用标准库和boost中的工具很难/不可能严格解析 我最终使用了
strtime
——大部分是\
计划以支持的格式列表为种子,顺序为
偏爱默认情况下,解析器是不自适应的(模式是固定的
)
在自适应模式下,可以要求
(始终重复使用第一个匹配的格式)sticky
(从列表中删除失败的模式;仅发生禁止 成功解析以避免禁止无效输入上的所有模式)ban_failed
(保留列表,但为性能重新排序)mru
- 注意:
如果格式不明确(例如,
vsmm-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";
}
}
只是时区的东西需要调整,主要是使用以下方法: 使用以下命令:
没有解释,但我非常感谢您在提供的链接中所做的工作!稍后我会更详细地阅读。你添加的语法糖也不错!没有解释,但我非常感谢您在提供的链接中所做的工作!稍后我会更详细地阅读。你添加的语法糖也不错!非常好…所以我猜你遇到了和我一样的不直观的事情-std/boost的人真的需要修复它!我当然也很欣赏你适应能力的灵活性——这正是我想要做的。假设它能工作(我肯定能),这看起来很棒。Boost的输入方面:很难知道什么是bug,什么不是由于未指定的契约造成的。但是,是的,它在我的书中是不可用的非常好…所以我猜你遇到了和我一样的不直观的东西-性病/艾滋病患者真的需要修复它!我当然也很欣赏你适应能力的灵活性——这正是我想要做的。假设它能工作(我肯定能),这看起来很棒。Boost的输入方面:很难知道什么是bug,什么不是由于未指定的契约造成的。但是是的,在我的书里它是不能用的
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 ?
#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