如何将 std::string_view 转换为双精度?

Posted

技术标签:

【中文标题】如何将 std::string_view 转换为双精度?【英文标题】:How to convert std::string_view to double? 【发布时间】:2017-08-11 14:30:32 【问题描述】:

我正在为应用程序的自定义选项文件编写 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 的确切部分,但我无法弄清楚从std::string_view 读取double 的方法.

我知道std::stod 不适用于std::string_view。它允许我写

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

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

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

那么,什么是干净、直观且相当有效的方法呢?

【问题讨论】:

你可以使用 boost 吗?我想你可以用boost::convert&lt;double&gt;(stringview); 做到这一点。我把它从这里弄下来了...页面上的最后评论github.com/boostorg/convert/issues/29 不错的发现。不过可能是boost::convert&lt;double&gt;(stringview, stringview.length())。它肯定比转换为字符串更干净,希望更快。唯一的缺点是对 boost 的额外依赖。 离题:显然这是伪代码,但要注意如何实现“while(not EOF)”。琐碎的while (!stream.eof()) 有一些令人讨厌的问题。 user4581301 通常,应该使用while ( stream &lt;&lt; statement ) 之类的东西... 请不要评论来自流部分的阅读。我专门用伪代码编写了它以保持讨论的重点。 【参考方案1】:

既然您用 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 的实现。

【讨论】:

from_chars() 采用 double&amp; 而不是 double*。这也是一个尴尬的界面......鉴于没有人提供它,也许这是一个很好的机会让它接受string_view...... @patatahooligan:“我建议将调用更改为”这仍然不起作用。 back最后一个 字符。它需要是一个指针过去最后一个字符。 @NicolBolas 您甚至不需要迭代器,只需使用 .data().data() + .size() 就可以了。 @patatahooligan 用两个论据来指称一件事是有问题的,称其为“通用”更糟糕。 @JeffreyBosboom double 版本即使在 gcc-10 中也没有实现。另一个&lt;regex&gt; 像惨败。【参考方案2】:

标题:

#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

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

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

更新:显然,许多 Boost 函数在内部使用字符串流,这对全局操作系统语言环境具有锁定。所以他们的多线程性能很糟糕**。

我现在推荐使用 substr 代替 stoi()。见:Safely convert std::string_view to int (like stoi or atoi)

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

【讨论】:

以上是关于如何将 std::string_view 转换为双精度?的主要内容,如果未能解决你的问题,请参考以下文章

将函数参数 `const char*` 转换为 `std::string_view` 是不是安全?

安全地将 std::string_view 转换为 int(如 stoi 或 atoi)

真的没有来自 std::string_view 的 std::string 的显式构造函数吗?

c++17比较string_view和string时的歧义

如何在 constexpr string_view 上使用 std::string_view::remove_prefix()

为啥 std::string_view 比 const char* 快?