问题 如何将std :: string_view转换为double?


我正在为应用程序的自定义选项文件编写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 包含我想要提取的值,但我无法弄清楚读取的方式 double 从一个 std::string_view

我知道 std::stod 哪个不起作用 std::string_view。它允许我写

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

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

另一方面, atof 将无法正常工作,因为我不能保证null终止符。我可以通过添加来破解它 \0 至 useful_statement 在构造它时,如果代码被更改/重构,这将使代码混淆读者并使其容易破解。

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


4349
2017-08-11 14:30


起源

使用boost是否可以?我想你可以这样做 boost::convert<double>(stringview);。我把它从这里开始......最后评论页面 github.com/boostorg/convert/issues/29 - Millie Smith
很好找。这可能是 boost::convert<double>(stringview, stringview.length())但是。它肯定比转换成字符串更清晰,希望更快。唯一的缺点是增加依赖性。 - patatahooligan
偏离主题:显然这是伪代码,但要注意你如何实现“while(而不是EOF)”。琐碎的 while (!stream.eof()) 有一些讨厌的陷阱。 - user4581301
user4581301通常,应该使用类似的东西 while ( stream << statement ) 代替… - Arne Vogel
请不要评论流部分的阅读。我特意用伪代码写它来保持讨论的重点。 - patatahooligan


答案:


由于您使用C ++ 1z标记了您的问题,那么(理论上)意味着您可以访问 from_chars。它可以处理你的字符串到数字的转换,而不需要任何东西 const char*S:

double dbl;
auto result = from_chars(&value_str[0], &value_str[0] + value_str.size(), dbl);

当然,这要求您的标准库提供实现 from_charsLibstdc ++没有,也不是 libc ++。或Visual Studio,就此而言。


11
2017-08-11 14:48



from_chars() 需要一个 double& 不是 double*。这也是一个尴尬的界面...鉴于没有人提供它,也许这是一个很好的机会让它采取一个 string_view... - Barry
如果实施的话,这正是我正在寻找的。我建议将通话更改为from_chars(&value_str.front(), &value_str.back(), dbl) 为了便于阅读,顺便说一句。 @Barry:没有太多理由去做 string_view 与...合作 char* 使它具有普遍性,从一个人那里得到它们是微不足道的 string_view。 - patatahooligan
@patatahooligan:“我建议将通话更改为“那仍然行不通。 back 是个 持续 字符。它需要是一个指针 过去 最后一个角色。 - Nicol Bolas
@NicolBolas你甚至不需要迭代器,可以使用 .data() 和 .data() + .size() 就像你基本上一样。 - Barry
@patatahooligan把两个论点引用一件事是值得怀疑的,称之为“普遍”更糟糕。 - Barry