我想使用 sscanf
创建一个简单的“日期”读取,它接受以下输入:
"dd/mm/yyyy"
“dd”和“mm”字段都可以是 2 位长(例如 0、6 或 11,但不能是 123)。 “年”字段可以是 0 或四位数字字段。这三个字段中的任何一个值为 0 都意味着必须取而代之的是系统的日、月或年。
该格式必须严格,因此,如果输入的格式不符合模式,则必须通知用户。
我的尝试是:
int d, m, y;
char const* input = "23/7/1990";
int n = sscanf(input, "%2u/%2u/%4u", &d, &m, &y);
if (n != 3) throw InvalidDate("Invalid format");
// Fill 0 values with system date.
// Check date correctness with `mktime` and `localtime`.
问题是这种 sscanf
格式接受不允许的输入:
char const* invalid1 = "23/ 12/ 1990";
char const* invalid2 = "23/12/1990/123whatever......."
那么,是否有任何技巧/修饰符可以拒绝整数前的前导零、标记字符串的结尾,或者在解析更多输入时导致可检测到的错误?
对于最后一种情况(invalid2;字符串末尾可检测到的故障),可能的解决方案是:
int d, m, y;
char trick;
char const* input = "23/7/1990";
int n = sscanf(input, "%2u/%2u/%4u%c", &d, &m, &y, &trick);
// If it fills four fields, means the input was too long.
if (fields != 3) throw InvalidDate("Invalid format");
// Fill 0 values with system date.
但我不知道是否有更好的方法来检测字符串结尾
。更重要的是,这种“格式”(以 '%c' 开头)导致 sscanf
认为输入的有效日期是错误的(例如,“23/6/1990”导致最后一个字符不是填充;如果使用 scanf
而不是 sscanf
,则会设置 ferror
)。我什至尝试过使用 "%2u/%2u/%4u\0"
但编译器警告我“格式嵌入\0”。
那么,不使用正则表达式或 stringstream
的最佳解决方案是什么?
对了,有没有其他方法可以“欺骗”sscanf
?
最佳答案
您可以使用 boost regex 库,它可以做很多这些事情。检查下面的代码:
#include <boost/regex.hpp>
#include <iostream>
#include <string>
int main()
{
// Expression to match
boost::regex e("(^\\d{1,2})/(\\d{1,2})/(\\d{4})$");
// Results are here
boost::match_results<std::string::const_iterator> results;
std::string val_to_match = "1/11/1990";
if (boost::regex_search(val_to_match, results, e) && results.size() == 4) {
std::cout << "Matched " << results[0] << std::endl;
int i = 1;
while (i < 4) {
std::cout << "Value: " << i << " "<< results[i] << std::endl;
i++;
}
} else {
std::cout << "Couldn't match \n";
}
return 0;
}
关于c++ - sscanf 拒绝整数读取中的前导零,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30275680/