gpt4 book ai didi

C++ boost date_input_facet 似乎使用传递给 facet 构造函数的不正确格式意外地解析日期

转载 作者:行者123 更新时间:2023-11-30 01:39:07 25 4
gpt4 key购买 nike

我用于测试的 coliru 中的玩具代码: http://coliru.stacked-crooked.com/a/4039865d8d4dad52

在长期中断 C++ 之后,我又开始习惯它了。我正在编写解析 CSV 的代码,该 CSV 可能包含多个包含日期或空值的列。我的假设是每个日期列都有一种有效的日期格式,尽管不同的列可能有不同的格式。

对于我拥有的每个日期列,我找到第一个被成功解析为日期的值,给定一个带有 boost date_input_facet 对象的潜在语言环境的 std::vector。正确解析的第一个日期将返回我的工作区域设置数组中的索引。一旦我为第一个可解析日期设置了合适的格式,我就想永远修复该格式,这样我就不必再浪费 CPU 时间来检测格式。

这是我的语言环境数组:

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 vector 的索引。

对于 20170101 到 201700129,它表示第 0 个索引有效,它应该具有带破折号的“%Y-%m-%d”格式?!?!此外,破折号所在的地方,我有数字,所以它被读取为 20170101 为 2017-10- 然后删除最后一个破折号并将其解释为 2017 年 10 月,没有日期的是 2017 年 10 月 1 日。为什么它不是那样做它应该使用的格式?

从我的 coliru 中可以看到的一些结果(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,报告了“%Y%m%d”的正确格式索引(第 5 个)。

有什么想法吗?我只想使用我传递的精确格式字符串。

最佳答案

我自己制作了一个支持多种格式的日期时间解析器。我也发现很难/不可能使用标准库和 boost 中的工具来严格解析。

我最终使用了 strptime - 主要是¹。

adaptive_parser

旨在按支持的格式列表播种偏爱。默认情况下,解析器不是自适应的(模式是 fixed)。

在自适应模式下,格式可能需要

  • sticky(始终重复使用第一个匹配的格式)
  • ban_failed(从列表中删除失败的模式;禁止仅发生成功解析以避免禁止无效输入的所有模式)
  • mru(保留列表但重新排序以 boost 性能)
  • Caution:
    If formats are ambiguous (e.g. mm-dd-yyyy vs dd-mm-yyyy) allowing re-ordering results in unpredictable results.

    ⇒ Only use mru when there are no ambiguous formats

  • NOTE:
    The function object is stateful. In algorithms, pass it by reference (std::ref(obj)) to avoid copying the patterns and to ensure correct adaptive behaviour

演示

我在您的测试数据上尝试了解析器:

#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 ?

¹ 主要是时区方面需要调整

关于C++ boost date_input_facet 似乎使用传递给 facet 构造函数的不正确格式意外地解析日期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46474237/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com