用户定义的字符串文字和模式与sscanf匹配
User defined string literal and pattern matching with sscanf
我之前发过一篇关于这件事的帖子,但那篇没有很好的解释,所以我删除了它,希望这篇会更好。现在我有两个关于以下代码的问题
#include <vector>
#include <sstream>
#include <iostream>
#include <cstdio>
#include <string>
using std::cerr;
using std::cout;
using std::cin;
using std::endl;
using std::string;
using std::vector;
int main() {
// the tests
vector<string> tests {"1.2 when 102"s, "1.2 1.2 1.2"s};
// format and the storage variables
string format {"%d %4s %d"};
int input_1 {-1};
char char_arr[5];
int input_2 {-1};
for (const auto& str : tests) {
cout << "Number of elements matched : ";
cout << std::sscanf(str.c_str(), format.c_str(), &input_1, char_arr,
&input_2) << endl;
cout << input_1 << endl;
cout << char_arr << endl;
cout << input_1 << endl;
}
return 0;
}
当我用clang(clang-703.0.29)在Mac上编译代码时,我得到以下错误
test.cpp:16:41: error: no matching literal operator for call to 'operator""s' with
arguments of types 'const char *' and 'unsigned long', and no matching literal
operator template
我认为用户定义的字符串文字是在C++14中完全实现的。为什么这个代码不编译?我可能在这里做一些非常愚蠢的事情。。。
如果我在删除文字后的s
后运行代码,那么我会得到以下输出
Number of elements matched : 2
1
.2
1
Number of elements matched : 3
1
.2
1
为什么input_2
在第一种情况下是1
?它不应该正确匹配,如果不是,那么为什么它是1
而不是-1
?
此外,如果我想在sscanf
调用中认为浮点数字无效,那么我应该在format
字符串中放入哪个转义符或标志?
您的s
字符串文字不起作用,因为该运算符位于命名空间std::literals::string_literals
中。添加适当的using
指令解决了这一问题。
我不相信使用sscanf
等人你所要求的是可能的,但如果你正在寻找一种高效、紧凑的方法来进行解析,并认为浮点数无效,那么我建议Boost。精神以下是使用Spirit的快速尝试。X3:
#include <tuple>
#include <string>
#include <vector>
#include <iostream>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/spirit/home/x3.hpp>
int main()
{
using namespace std::string_literals;
namespace x3 = boost::spirit::x3;
auto const format =
x3::int_ >> ' ' >> x3::repeat(4)[x3::print] >> ' ' >> x3::int_ >> x3::eoi;
std::vector<std::string> const tests{"1.2 when 102"s, "1.2 1.2 1.2"s,
"12 when 142"s, "12 foo 142"s};
for (auto const& str : tests)
{
int input_1 = -1;
std::string chars;
int input_2 = -1;
auto attr = std::tie(input_1, chars, input_2);
auto const success = x3::parse(cbegin(str), cend(str), format, attr);
std::cout
<< '"' << str << "" :: parse " << (success ? "succeeded" : "failed") << 'n'
<< input_1 << 'n'
<< chars << 'n'
<< input_2 << "nn";
}
}
在线演示
这个解析器非常严格——它要求字段之间只有一个空格,字符串字段只有四个可打印字符,并且不允许前导或尾随空格。Spirit可以非常轻松地放宽所有这些要求,如果在运行时出现错误,则具有编译时安全性,而不是UB/内存损坏。
EDIT:与sscanf
等不同,Spirit甚至可以避免复制字符串字段的数据,只要输入字符串数据稳定:
#include <tuple>
#include <string>
#include <vector>
#include <iostream>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/spirit/home/x3.hpp>
int main()
{
using namespace std::string_literals;
namespace x3 = boost::spirit::x3;
auto const format =
x3::int_ >> ' ' >> x3::raw[x3::repeat(4)[x3::print]] >> ' ' >> x3::int_ >> x3::eoi;
std::vector<std::string> const tests{"1.2 when 102"s, "1.2 1.2 1.2"s,
"12 when 142"s, "12 foo 142"s};
for (auto const& str : tests)
{
int input_1 = -1;
boost::iterator_range<std::string::const_iterator> chars;
int input_2 = -1;
auto attr = std::tie(input_1, chars, input_2);
auto const success = x3::parse(cbegin(str), cend(str), format, attr);
std::cout
<< '"' << str << "" :: parse " << (success ? "succeeded" : "failed") << 'n'
<< input_1 << 'n'
<< chars << 'n'
<< input_2 << "nn";
}
}
在线演示
%d匹配一个整数。"1.2"不是整数,因此%d只与"1"部分匹配。从这一点开始,一切都偏离了轨道。
相关文章:
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 用C++中的sscanf赋值
- 为什么在保护模式下继承升级不起作用
- 为什么 sscanf 无法从一个字符串中读取uint64_t和字符?
- 如何在全屏模式下(在OpenGL中)使背景透明
- 为什么使用__LINE_的代码在发布模式下在MSVC下编译,而不是在调试模式下
- 派生类是否可以在抽象工厂设计模式中具有数据成员
- 此模式的C++RegEx
- avrogencpp能为模式中的每种类型生成单独的头文件吗
- 使用可变模板的Broadcaster/Listener模式
- c++方法参数只能在linux的发布模式下自行更改
- 具有结构成员char数组的sscanf
- 资源管理设计模式
- 使用 mod_gsoap 部署服务时,如何在 Gsoap 中更改 soap 上下文的模式?
- C++ 无法在字符数组中使用 for 循环打印字母模式
- 小字符串优化(调试与发布模式)
- 可视化C++:发布模式的运行时库作为'Multi-threaded Debug DLL'
- 在 Arduino 上使用 sscanf 会导致与 const char * 不匹配,并且返回值始终相同,尽管输入值不同
- 用户定义的字符串文字和模式与sscanf匹配
- C++在sscanf模式方面遇到问题