boost::posix_time格式标志异常行为的原因咨询
解析boost::posix_time::ptime时".*+A"格式生效的原因
核心原理:boost时间解析的容错机制
boost的time_input_facet不支持正则表达式,格式字符串的规则和正则完全不同:
- 仅以
%开头的序列是格式说明符(如%Y匹配4位年份),其余字符均为字面量,要求与输入严格匹配; - 当字面量无法匹配当前输入字符时,解析器会触发容错逻辑:持续跳过输入字符,直到找到能匹配后续格式说明符或字面量的位置。
你的格式字符串.*+A%Y%m%d.%H%M能成功解析第二个时间戳,本质是:
- 开头的
.*+A都是普通字面量,和输入开头的ASTRO20220923.1435+0000-完全不匹配; - 解析器不断跳过输入字符,直到遇到
%Y对应的4位数字序列(即第二个时间戳的2022); - 后续的
%m%d.%H%M完美匹配0923.1440,最终成功解析出第二个时间。
换句话说,.*+A只是一个无效前缀,解析器因匹配失败跳过了所有前置无关内容,刚好命中第二个时间戳的起始位置——这是容错机制带来的意外结果,并非.+有特殊格式含义。
规范的替代写法
依赖容错的写法非常不可靠,换输入格式就会失效,推荐两种规范方式:
1. 拆分字符串后分别解析
先提取两个时间戳的子串,再各自用对应格式解析:
#include <iostream> #include <boost/date_time/posix_time/posix_time.hpp> #include <string> int main() { std::string timeStr = "ASTRO20220923.1435+0000-20220923.1440+0000"; size_t dashPos = timeStr.find('-'); std::string startStr = timeStr.substr(0, dashPos); std::string endStr = timeStr.substr(dashPos + 1); boost::posix_time::ptime pTimeStart; std::stringstream ssStart(startStr); ssStart.imbue(std::locale(ssStart.getloc(), new boost::posix_time::time_input_facet("ASTRO%Y%m%d.%H%M"))); ssStart >> pTimeStart; std::cout << "START: " << boost::posix_time::to_simple_string(pTimeStart) << std::endl; boost::posix_time::ptime pTimeEnd; std::stringstream ssEnd(endStr); ssEnd.imbue(std::locale(ssEnd.getloc(), new boost::posix_time::time_input_facet("%Y%m%d.%H%M"))); ssEnd >> pTimeEnd; std::cout << "END : " << boost::posix_time::to_simple_string(pTimeEnd) << std::endl; return 0; }
2. 使用%*格式说明符跳过无关内容
boost支持%*格式说明符,用于跳过任意字符直到指定匹配项:
#include <iostream> #include <boost/date_time/posix_time/posix_time.hpp> int main() { std::string timeStr = "ASTRO20220923.1435+0000-20220923.1440+0000"; std::stringstream ss; boost::posix_time::ptime pTimeStart; ss.imbue(std::locale(ss.getloc(), new boost::posix_time::time_input_facet("ASTRO%Y%m%d.%H%M"))); ss << timeStr; ss >> pTimeStart; std::cout << "START: " << boost::posix_time::to_simple_string(pTimeStart) << std::endl; // 重置流状态和内容,用%*[^-]跳过第一个时间戳到'-',再匹配'-'后解析时间 ss.clear(); ss.str(timeStr); boost::posix_time::ptime pTimeEnd; ss.imbue(std::locale(ss.getloc(), new boost::posix_time::time_input_facet("%*[^-]-%Y%m%d.%H%M"))); ss >> pTimeEnd; std::cout << "END : " << boost::posix_time::to_simple_string(pTimeEnd) << std::endl; return 0; }
这里%*[^-]表示跳过所有非-的字符,直到遇到-,再匹配-后解析后续时间。
总结
你之前的写法是依赖解析器容错的巧合,并非规范用法。使用字符串拆分或%*格式说明符的写法更清晰、更可靠。
内容的提问来源于stack exchange,提问作者nanika
相关产品推荐
相关产品推荐

