24

我正在为应用程序的自定义选项文件编写 C++ 解析器。option=value我有一个循环,它以文本文件的形式读取行,value必须将其转换为double. 在伪代码中,它执行以下操作:

while(not EOF)
    statement <- read_from_file
    useful_statement <- remove whitespaces, comments, etc from statement
    equal_position <- find '=' in useful_statement
    option_str <- useful_statement[0:equal_position)
    value_str <- useful_statement[equal_position:end)
    find_option(option_str) <- double(value_str)

为了处理字符串拆分和传递给函数,我使用std::string_view它是因为它避免了过度复制并清楚地说明了查看预先存在的std::string. 我已经做了所有事情,指向包含我要提取的值std::string_view value_str的确切部分useful_statement,但我无法弄清楚doublestd::string_view.

我知道std::stod哪个不适用于std::string_view. 它允许我写

double value = std::stod(std::string(value_str));

但是,这很难看,因为它会转换为实际上不需要的字符串,即使在我的情况下它可能不会产生明显的差异,但如果必须从文本中读取大量数字,它可能会太慢文件。

另一方面,atof因为我不能保证一个空终止符,所以它不起作用。我可以在构造它时添加\0to来破解它useful_statement,但这会使代码对读者感到困惑,并且如果代码被更改/重构,它也很容易被破坏。

那么,什么是干净、直观和合理有效的方法呢?

4

2 回答 2

24

既然您用 C++1z 标记了您的问题,那么(理论上)意味着您可以访问from_chars. 它可以处理您的字符串到数字的转换,而无需超过一对const char*s:

double dbl;
auto result = from_chars(value_str.data(), value_str.data() + value_str.size(), dbl);

当然,这要求您的标准库提供from_chars.

于 2017-08-11T14:48:56.230 回答
3

标题:

#include <boost/convert.hpp>
#include <boost/convert/strtol.hpp>

然后:

std::string x { "aa123.4"};
const std::string_view y(x.c_str()+2, 5); // Window that views the characters "123.4".

auto value = boost::convert<double>(y, boost::cnv::strtol());
if (value.has_value())
{
    cout << value.get() << "\n"; // Prints: 123.4
}

测试编译器:

  • MSVC 2017

ps 可以使用 vcpkg 轻松安装 Boost(默认为 32 位,第二个命令用于 64 位):

vcpkg install boost-convert
vcpkg install boost-convert:x64-windows

更新:显然,许多 Boost 函数在内部使用字符串流,这对全局 OS 区域设置有锁定。所以他们的多线程性能很糟糕**。

我现在会推荐类似stoi()substr 的东西。请参阅:安全地将 std::string_view 转换为 int(如 stoi 或 atoi)

** Boost 的这个奇怪的怪癖使得大多数 Boost 字符串处理在多线程环境中完全无用,这确实是一个奇怪的悖论。这是来之不易的经验之声——如果您有任何疑问,请自行衡量。与 2 核机器相比,48 核机器运行许多 Boost 调用并不快。所以现在我避免了 Boost 的某些部分,比如众所周知的瘟疫,因为任何东西都可能依赖于那个该死的全局操作系统语言环境锁。

于 2019-09-16T20:24:38.637 回答