std::字符串到整数/双倍在一次传递中

std::string to int / double in one pass

本文关键字:一次 字符串 整数 std      更新时间:2023-10-16

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

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

有没有某种函数可以在一次传递中解析两种类型?还是我首先必须手动查找点并调用正确的函数?

谢谢。:)

您不会找到一个标准调用来实现这一点,原因很简单,没有点的数字字符串既是有效的整数又是有效的双精度。

如果您的标准是"双当且仅当点",请手动查找点。或者,读作双精度并检查小数部分是否为空。

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

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。恕我直言,熟悉这些构建块比学习如何滚动自己的构建块更有价值。

你应该自己解析它,使用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 请参阅文章整数文本和浮点文本。

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

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