ph4*_*t0m 11 c++ parsing scanf
假设我的程序需要表单的参数[ 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;
Run Code Online (Sandbox Code Playgroud)
我怎么能改进这段代码?特别是,我关注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;
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用这样的构建操纵器来提取字符:
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";
}
}
Run Code Online (Sandbox Code Playgroud)
我可以负担得起,可以使用精神。
看到
从string
Live On Coliru(在c ++ 03中):
更新下面是如果你实际上是试图从流读取方法(它实际上有些简单,并集成真的很好与其他流读书活动):
住在Coliru太(C ++ 03)
Allthough这似乎更详细的,精神也是很多更强大,类型安全比sscanf
。它在流上运行。
还要注意的是inf
,-inf
,nan
将如预期进行处理。
#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;
}
}
Run Code Online (Sandbox Code Playgroud)