std::string 到 int / double 一次通过

std::string to int / double in one pass

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

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

是否有某种函数可以一次解析这两种类型?还是我必须先手动寻找一个点并调用正确的函数?

谢谢。 :)

您找不到实现此目的的标准调用,原因很简单,不带点的数字串既是有效整数又是有效双精度数。

如果您的标准是"double if and only if dot",则手动寻找圆点。或者,读取为 double 并检查小数部分是否为空。

请自行解析,使用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 literal and floating-point literal 了解可能的模式。

由于这个困难,许多词法分析器只是将输入标记化(用空格分隔)并检查完整标记是否与任何有效表示匹配。 我想,如果你不知道输入是整数还是近似实数,就用std::stof解析它。

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

既然你说过(在上面的评论中)简单的点符号就是你想要的实数,并且你想要一次通过(即没有回退到已经解析的输入),并且(再次来自你的评论)更多的是在编程经验之后而不是效率/可维护性/可扩展性,这个怎么样:

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 returns index,但 stod 需要 string .所以我必须做一个 substr() 或类似的,而 C 函数使用指针,使事情变得更容易。

我在评论中所说的是正确的:作为大脑实验,这具有一定的价值,但任何 真正的 解析工作都应该利用现有的解决方案,例如 Boost.Spirit .恕我直言,熟悉此类构建块 比学习如何自己动手更有价值