用sscanf解析输入的C++替代方案
C++ alternative for parsing input with sscanf
假设我的程序需要形式为[ 0.562 , 1.4e-2 ]
的参数(即浮点对),那么在没有正则表达式的情况下,我应该如何在C++中解析此输入?我知道当涉及到用户输入时,有很多角落的情况需要考虑,但让我们假设给定的输入与上面的格式非常匹配(除了更多的空白)。
在C中,我可以做一些类似sscanf(string, "[%g , %g]", &f1, &f2);
的事情来提取两个浮点值,这是非常紧凑的。
在C++中,这就是我迄今为止所想到的:
std::string s = "[ 0.562 , 1.4e-2 ]"; // example input
float f1 = 0.0f, f2 = 0.0f;
size_t leftBound = s.find('[', 0) + 1;
size_t count = s.find(']', leftBound) - leftBound;
std::istringstream ss(s.substr(leftBound, count));
string garbage;
ss >> f1 >> garbage >> f2;
if(!ss)
std::cout << "Error while parsing" << std::endl;
如何改进此代码?特别是,我关心的是garbage
字符串,但我不知道如何跳过这两个值之间的,
。
显而易见的方法是创建一个简单的操纵器并使用它。例如,一个操纵器使用静态提供的char
来确定下一个非空白字符是否是该字符,如果是,则提取它可能如下所示:
#include <iostream>
#include <sstream>
template <char C>
std::istream& expect(std::istream& in)
{
if ((in >> std::ws).peek() == C) {
in.ignore();
}
else {
in.setstate(std::ios_base::failbit);
}
return in;
}
然后,您可以使用由此构建的操纵器来提取字符:
int main(int ac, char *av[])
{
std::string s(ac == 1? "[ 0.562 , 1.4e-2 ]": av[1]);
float f1 = 0.0f, f2 = 0.0f;
std::istringstream in(s);
if (in >> expect<'['> >> f1 >> expect<','> >> f2 >> expect<']'>) {
std::cout << "read f1=" << f1 << " f2=" << f2 << 'n';
}
else {
std::cout << "ERROR: failed to read '" << s << "'n";
}
}
我可以用boost,你可以用Spirit。
参见
-
来自Coliru上的
string
直播(在c++03中): -
更新如果你真的试图从流中阅读,这里有一种方法(它实际上有点简单,并且与其他流阅读活动很好地集成了):
也在Coliru上直播(c++03)
尽管这看起来更为冗长,但Spirit也比sscanf
功能强大且类型安全。它在流上运行。
还要注意,inf
、-inf
、nan
将按预期进行处理。
在Coliru上直播
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_match.hpp>
#include <sstream>
namespace qi = boost::spirit::qi;
int main()
{
std::istringstream ss("[ 0.562 , 1.4e-2 ]"); // example input
ss.unsetf(std::ios::skipws); // we might **want** to handle whitespace in our grammar, not needed now
float f1 = 0.0f, f2 = 0.0f;
if (ss >> qi::phrase_match('[' >> qi::double_ >> ',' >> qi::double_ >> ']', qi::space, f1, f2))
{
std::cout << "Parsed: " << f1 << " and " << f2 << "n"; // default formatting...
} else
{
std::cout << "Error while parsing" << std::endl;
}
}
除了正则表达式之外,Boost中可能还有一些东西可以使用。但是,如果您不能使用Boost,那么您可以定义一个std::ctype<char>
方面,通过将所有不必要的字符分类为空白来有效地忽略它们。您可以将这个方面安装到一个区域设置中,并将其注入ss
中。
- 运行同一解决方案的另一个项目的项目
- Project Euler问题4的错误解决方案
- 计算每个节点的树高,帮助我解释这个代码解决方案
- C++:Application.cpp中抛出了未解析的外部符号(解决方案在问题的末尾,供未来的读者参考)
- visual c++,如何获取解决方案目录中的代码
- 有没有办法在远程设备上打开和编辑visual Studio 2017解决方案
- C++Matching Brackets 2解决方案不起作用
- 在 ubuntu3 上C++ goto 定义有什么解决方案吗16.04?
- C++11 中不同类型的对象的 std::array 的替代方案
- 在 leetcode 上提交解决方案时出现堆栈缓冲区溢出错误
- 别名模板的专业化 C++11 中没有开销的最佳替代方案
- 我的固定时间步长与增量时间和插值的解决方案是错误的吗?
- 无法在问题解决方案中执行输出逻辑
- 最大的回文产品 - 程序未运行,编写解决方案但无法理解问题
- 从预序遍历构造 bst 的 c++ 和 python 解决方案之间的区别
- 在一个解决方案中针对第三方静态库 (Creo) 的不同版本(版本)进行构建
- 如何巧妙地编写两个函数——一个用于检查是否存在解决方案,另一个用于获取所有解决方案
- 使用 Git 处理 C++ Visual Studio 2019 解决方案的外部依赖项源代码管理的最佳方法是什么?
- N-queen问题:无法弄清楚为什么我的解决方案不起作用
- 从排序数组中删除重复项,具有不同代码方式的相同解决方案具有不同的输出