繁体   English   中英

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

[英]Safer but easy-to-use and flexible C++ alternative to sscanf()

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

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

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

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

我写了一些可以读取字符串和字符文字的代码。 与普通流读取一样,如果它获得无效数据,则设置流的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);
}

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

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

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

编辑

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

我用过字符串解析的最好的东西是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

我认为使用正则表达式可以轻松完成。 所以在新标准中使用boost :: regex或std :: regex。 之后,直接使用lexical_cast或stream将您的标记转换为浮动。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM