更安全但易于使用且灵活的C++替代sscanf()

Jas*_*n R 22 c++ string parsing scanf

当我需要扫描一堆字符串中的值时,我经常发现自己sscanf()严格地回到C语言,因为它简单易用.例如,我可以非常简洁地从字符串中拉出几个double值:

string str;
double val1, val2;
if (sscanf(str.c_str(), "(%lf,%lf)", &val1, &val2) == 2)
{
    // got them!
}
Run Code Online (Sandbox Code Playgroud)

这显然不是很C++.我不一定认为这是一种憎恶,但我总是在寻找一种更好的方法来完成一项共同的任务.我理解读取字符串的"C++方式"是istringstream,但是处理上面的格式字符串中的括号和逗号所需的额外输入只会使得我想要使用它太麻烦.

是否有一种很好的方法可以以类似于上面的方式将内置设施弯曲到我的意愿,或者是否有一个好的C++库以更加类型安全的方式完成上述操作?看起来Boost.Format确实以一种很好的方式解决了输出问题,但我没有发现任何类似的输入简洁.

Moo*_*uck 15

我写了一些可以读取字符串和字符文字的代码.与普通流读取一样,如果它获得无效数据,则设置流的badbit.这适用于所有类型的流,包括宽流.将此位粘贴在新标题中:

#include <iostream>
#include <string>
#include <array>
#include <cstring>

template<class e, class t, int N>
std::basic_istream<e,t>& operator>>(std::basic_istream<e,t>& in, const e(&sliteral)[N]) {
        std::array<e, N-1> buffer; //get buffer
        in >> buffer[0]; //skips whitespace
        if (N>2)
                in.read(&buffer[1], N-2); //read the rest
        if (strncmp(&buffer[0], sliteral, N-1)) //if it failed
                in.setstate(in.rdstate() | std::ios::failbit); //set the state
        return in;
}
template<class e, class t>
std::basic_istream<e,t>& operator>>(std::basic_istream<e,t>& in, const e& cliteral) {
        e buffer;  //get buffer
        in >> buffer; //read data
        if (buffer != cliteral) //if it failed
                in.setstate(in.rdstate() | std::ios::failbit); //set the state
        return in;
}
//redirect mutable char arrays to their normal function
template<class e, class t, int N>
std::basic_istream<e,t>& operator>>(std::basic_istream<e,t>& in, e(&carray)[N]) {
        return std::operator>>(in, carray);
}
Run Code Online (Sandbox Code Playgroud)

它将使输入字符变得非常容易:

std::istringstream input;
double val1, val2;
if (input >>'('>>val1>>','>>val2>>')') //less chars than scanf I think
{
    // got them!
}
Run Code Online (Sandbox Code Playgroud)

概念证明.现在你可以使用cin字符串和字符文字,如果输入不是完全匹配,它就像任何其他未能正确输入的类型一样.请注意,这仅匹配不是第一个字符的字符串文字中的空格.它只有四个功能,所有功能都是脑死亡的简单功能.

编辑

解析流是一个坏主意.使用正则表达式.

  • @MooingDuck这是一个非常棒的片段,我打算使用它来删除项目中的一些旧C代码,并用它替换它. (2认同)

sli*_*ser 6

我用过字符串解析的最好的东西是boost.spirit.它快速,安全且非常灵活.最大的优点是您可以以接近EBNF语法的形式编写解析规则

using namespace boost::spirit;

boost::fusion::vector < double, double > value_;

std::string string_ = "10.5,10.6 ";

bool result_ = qi::parse(
    string_.begin(),
    string_.end(),
    qi::double_ >> ',' >> qi::double_, // Parsing rule
    value_); // value
Run Code Online (Sandbox Code Playgroud)