C++17: string_view 转换为整数类型






2.94/5 (7投票s)
使用 Boost Spirit Qi v2 实现 string_view 到整数类型的转换
- 下载 floatbench-1.1.2.zip - 83.5 KB
- 下载 intbench-1.1.0.zip - 8.8 KB
- 下载 str_view_conv_ex-1.0.1.zip - 9.2 KB
目录
原理
在开始讨论 string_view
之前,我们必须重新审视一个 C API:strtok()
,其目的是将 char
数组拆分为标记。
char * strtok ( char * str, const char * delimiters );
#include <cstdio> #include <algorithm> int main() { using namespace std; char str[] = "Apple,Orange,Mango"; /* dup_arr will contains str later */ char dup_arr[sizeof(str)]; const char s[2] = ","; char *token; /* display str address */ printf("str address:%p\n", str); /* get the first token */ token = strtok(str, s); /* walk through other tokens */ while (token != NULL) { /* display token */ printf("%s\n", token); /* display token address */ printf("token address:%p\n", token); /* copy str into dup_arr */ memcpy(dup_arr, str, sizeof(dup_arr)); /* replace the null char with \x35 which is # */ std::replace(begin(dup_arr), end(dup_arr)-1, 0, 35); /* display dup_arr */ printf("%s\n", dup_arr); /* get next token */ token = strtok(NULL, s); } return(0); }
输出如下所示。 我添加了 ^
来指示 token
在 str
中的指向位置。 我使用 #
表示空终止符,因为它是一个不可打印的字符。
str address:008FF704 Apple token address:008FF704 Apple#Orange,Mango ^ Orange token address:008FF70A Apple#Orange#Mango ^ Mango token address:008FF711 Apple#Orange#Mango ^
strtok
有两个问题:它会修改 str
参数,但它的优点是它非常快,因为它不必为标记分配字符串。 另一个问题是它无法拆分带有空标记的字符串:例如:",,"
,因为它会变成 "##"
,并导致 strtok
返回 null,这会过早地向客户端代码发出信号,表明它已到达 str
的末尾。 这就是 C++17 string_view
拯救的地方:string_view
包含一个 char
指针和一个 size
作为数据成员,并包含许多 std::string
拥有的有用成员函数。 它的长度不包括空终止符,这意味着 string_view
不必以空值结尾,这使其成为编写 C++17 constness 正确 strtok
的理想候选者。 但本文不是关于编写 string_view
版本的 strtok
的。
这种原地字符串修改广泛用于快速 XML DOM 解析器,例如 RapidXML 和 Pugixml。 RapidJSON 是一个 JSON 解析器,它也使用了这个特性。
// original xml text <Fruit name="Orange" type="Citrus" /> // mutated xml text <Fruit#name#"Orange# type#"Citrus# /> ^ ^ ^ ^ ^
如果文本是严格不可变的并且需要进行转义(如下所示),或者文本被修改为更长,则 XML 解析器无法完全避免字符串分配。
<Food name="Ben & Jerry" type="Ice Cream" /> "Ben & Jerry" needs to be unescaped to "Ben & Jerry"
转换为浮点数和整数
对于转换,我们使用 Boost Spirit Qi。 str_to_value
是一个重载的模板函数,它适用于 std::string
、string_view
和 char
数组(不是 char
指针)。 为了演示目的,我们使用 Boost string_ref
,因为 Visual C++ 尚不可用 string_view
。 为了简单起见,未显示其他重载。 读者可以在 str_to_value.h
中查看它们。 支持 float
、short
、long
和 long long
以及它们的 unsigned
对应物。
#include <string> #include <iostream> #include <boost/utility/string_ref.hpp> #include <boost/spirit/include/qi.hpp> template<typename string_type> inline bool str_to_value(const string_type& src, double& dest) { namespace qi = boost::spirit::qi; return qi::parse(std::cbegin(src), std::cend(src), qi::double_, dest); } template<typename string_type> inline bool str_to_value(const string_type& src, int& dest) { namespace qi = boost::spirit::qi; return qi::parse(std::cbegin(src), std::cend(src), qi::int_, dest); } int main(int argc, char *argv []) { boost::string_ref srd("123.456"); double d = 0.0; if (str_to_value(srd, d)) { std::cout << d << std::endl; // display 123.456 } boost::string_ref srn("123"); int n = 0; if (str_to_value(srn, n)) { std::cout << n << std::endl; // display 123 } return 0; }
Boost Spirit Qi 基准测试
C++ 字符串到 Double 基准测试(循环 100 万次)
1.1.1 版 double 基准测试
最新的 double 基准测试,它修复了 crack_atof
科学计数法转换问题,并将性能提高了 10%,使其与 fast_atof
相当。
atof: 100ms lexical_cast: 648ms std::istringstream: 677ms <== Probably unfair comparison since istringstream instaniate a string std::stod: 109ms std::strtod: 96ms crack_atof: 7ms fast_atof: 7ms <== do not use this one because conversion is not correct. boost_spirit: 17ms <== reported to be inaccurate in some case google_dconv: 38ms std::from_chars: 71ms
C++ 字符串到整数基准测试(循环 1000 万次)
atol: 243ms lexical_cast: 952ms std::istringstream: 5338ms std::stoll: 383ms simple_atol: 74ms sse4i_atol: 72ms boost_spirit: 78ms std::from_chars: 59ms
摘要
- 最初,
string_view
在 Boost 中被称为string_ref
- String view 未以 null 结尾,因此无法使用
atoi()
- 使用 Boost Spirit Qi
- 可用于
std::string
、char 数组。 不支持 char ptr - 或者任何具有
cbegin()
和cend()
的类 - 警告:有人报告 Boost Spirit Qi 浮点转换不准确
- 可用于
相关的源代码存储库如下。
历史
- 2016 年 10 月 1 日:首次发布
- 2017 年 4 月 5 日:使用
strtod
和 Google double 转换 更新了 string-to-float 基准测试 - 2018 年 6 月 6 日:上传了 floatbench 1.1.0,它修复了
crack_atof()
科学计数法转换问题,其性能提高了 10%。 感谢 Tian Bo。 - 2018 年 6 月 7 日:上传了 intbench 1.1.0,其中包含基准测试中的
std::from_chars
。std::from_chars
需要 C++17 支持,并且 VC++ 在编译浮点转换时存在问题,因此目前仅在 intbench 中添加。 - 2018 年 10 月 27 日:上传了 floatbench 1.1.2,其中包含来自 VS 2018 Update 15.8 的
std::from_chars
进入基准测试。