一次传递std :: string到int / double

时间:2015-06-15 07:33:24

标签: c++ string parsing c++11 std

我正在解析一个字符串,该字符串可能包含实数或整数值。我想解析该字符串,并在单个解析中获得整数或实数值。

我可以使用std :: stoi和std :: stod,但如果我先调用stoi并且它是真实的,那么它将失败并且我将不得不调用stof,导致第二次解析。如果我首先调用stof并且该字符串包含一个整数,那么它会将其视为有效的实数值,从而丢失它是一个整数的信息。

是否有某种函数可以在一次传递中解析这两种类型?或者我首先要手动寻找一个点并调用正确的函数吗?

谢谢。 :)

3 个答案:

答案 0 :(得分:1)

你不会找到一个标准的调用来实现这个,原因很简单,一个没有点的数字串都是一个有效的整数和一个有效的double。

如果您的标准为"当且仅当dot"时加倍,则手动查找点。或者,读为double并检查小数部分是否为空。

答案 1 :(得分:1)

既然你说(在上面的评论中)简单的点符号是你想要的实数,你想要一次通过(即没有后退到已经解析过的输入),并且(再次从你的评论中) )在编程经验之后比效率/可维护性/可扩展性更多,如何:

char const * input = /*...*/;
char const * parse_end;
size_t pos;
size_t pos2 = 0;

// parse integer (or pre-digit part of real)
int integer = strtol( input, &parse_end, 10 );

if ( *parse_end == '.' )
{
    // you have a real number -- parse the post-digit part
    input = parse_end;
    double real = strtod( input, &parse_end );
    // real + integer is your result
}
else
{
    // integer is your result
}

// in either case, parse_end is your position

为什么我使用C函数... stoi返回索引,但stod需要string。所以我必须做substr()或类似的,而C函数使用指针,使事情变得更容易。

我在评论中所说的内容是正确的:作为大脑实验,它具有一定的价值,但任何真正的解析工作都应该使用现有的解决方案,如Boost.Spirit。熟悉这些构建模块,恕我直言,更多比学习如何推销自己更有价值。

答案 2 :(得分:0)

您应该使用std::string::substrstd::string::find_first_ofstd::string::find_first_not_of等自行解析。

如您所知,std::stoistd::stof中的每一个都解释了与所需类型的右表示模式匹配的第一个最长子字符串。如果可能的话,你可能会认为积分解析的结果总是不同的实数解析结果,但它不是。

示例1:考虑"123."std::stoi将解析子字符串"123",而std::stof将解析整个"123.""123."是一个有效的浮点字面值,但它代表一个精确的整数。

示例2:考虑"123.0"。这是一个微不足道的实际价值表示。 std::stoi将解析子字符串"123",而std::stof将解析整个"123.0"。两个结果在算术上是相同的。

这是您应该决定解析什么以及不解析什么的地方。有关可能的模式,请参阅cppreference.com文章integer literalfloating-point literal

由于存在这些困难,许多词法分析器只是将输入标记化(用空格分隔)并检查完整标记是否与任何有效表示匹配。 我认为,如果您不知道输入是完整的还是近似的,只需通过std :: stof解析。

此外,将float转换为int的某些解决方案会导致错误的行为。具有整数值的float类型变量不能保证等于具有相同整数值的int类型变量。这是因为float,通常编译为使用float32_t(IEEE 754-1985单/ IEEE 754-2008二进制32)具有24位宽的有效数。因此,适合32位有符号的整数的有效字符串表示可能不适合float。你失去了精确度。与int32_t相比,double,通常是IEEE 754-2008 binary64,不会丢失有效宽度,但与int64_t相同,等等。