C++学习笔记----Strings与String View(6)-- 数字类型转换

        在操作string的过程中,与数字类型的相互转换是必不可少的,本次我们就来看一下字符串与数字类型转换的相关内容,其转换分为高阶转换与低阶转换,详述如下:

1、高阶数字转换

1.1数字转字符串

        这个比较简单吧:

string to_string(T val);

        那就简单做一下解释:将类型为T的val转换成字符串,其中T的类型可以是:(unsigned) int, (unsigned) long, (unsigned) long long, float, double, 或者是long double。当然了,我们在学习C++,即使是牵涉到字符串,我们也不必考虑内存的申请与释放的问题了,这个是默认的,以后就不再赘述了。好的,我们再简单看个例子:

import std;
using namespace std;
int main()
{
	long double d{ 3.14L };
	string s{ to_string(d) };
	println("long double d {}", d);
	println("to_string(d={})", s);
	return 0;
}

结果如下:

long double d 3.14
to_string(d=3.140000)

是很简单吧。

1.2字符串转数字

        其实字符串转数字的概念也比较好理解,不多做解释,直接上干货

int stoi(const string& str, size_t *pos = nullptr, int base = 10);
long stol(const string& str, size_t *pos = nullptr, int base = 10);
unsigned long stoul(const string& str, size_t *pos = nullptr, int base = 10);
long long stoll(const string& str, size_t *pos = nullptr, int base = 10);
unsigned long long stoull(const string& str, size_t *pos = nullptr, int base = 10);
float stof(const string& str, size_t *pos = nullptr);
double stod(const string& str, size_t *pos = nullptr);
long double stold(const string& str, size_t *pos = nullptr);.

        这么多,这么复杂,还说好理解,你是不是在骗我们哦,说真的,不骗你们,且听我娓娓道来,你耐心一点,我细致一点,我们win-win好不好。

        先解释一下函数名字的含义,其中s肯定代表string字符串了,to代表转换,i代表integer整型,l代表long integer长整型,ul代表unsigned long无符号长整型,ll代表long long integer长长整型,ull代表unsigned long long无符号长长整型,f代表float浮点型,d代表double双精度浮点型;函数中的str表示的对字符串的引用,pos指针指向第一个无法转换的字符串的位置,base是指进制,我们通常用到的是2、8、10、16进制,默认是10进制的,这里需要注意的是,如果我们将base设置为0,那就是告诉编译器,你自己判断要转换的进制吧,系统会按如下规则进行判断,如果数字以0x或者0X开头,则为16进制,如果数字以0开头,则为8进制,其他的都按10进制来看待。话不多说,上例子:

import std;
using namespace std;
int main()
{
	const string toParse{ "    123USD" };
	size_t index{ 0 };
	int value{ stoi(toParse, &index) };
	println("Parsed value: {}", value);
	println("第一个无法解析的字符: '{}'", toParse[index]);

	const string basezero_toParse{ "0x345abUSD" };
	unsigned long basezero_value{ stoul(basezero_toParse,&index,0) };
	println("字符串{}转数字{:X}", basezero_toParse, basezero_value);

	return 0;
}

看结果:

Parsed value: 123
第一个无法解析的字符: 'U'
字符串0x345abUSD转数字345AB

这里面其实没有多少好解释的,但是,多啰嗦点与字符串相互转换无关的,大家有没有注意到,我在输出时写了一句

        println("字符串{}转数字{:X}", basezero_toParse, basezero_value);

其中的{:X}是否有点疑惑,如果没有,你可以跳过下面的解释了,如果有那么一点点,那我就多解释一下:其实这是println的格式化输出,其中的X代表的是大写十六进制中的ABCDE,其他的数字格式化输出如下:

要将数字格式化为其他进制,可以使用以下格式说明符:

  • d:十进制(默认)
  • x:十六进制(小写字母)
  • X:十六进制(大写字母)
  • o:八进制
  • b:二进制(小写字母)
  • B:二进制(大写字母)

2、低阶数字转换

        低阶数字转换不使用std::string类,说到底,就是又回到了C语言时代的离计算机底层更近,操作更灵活,包装少。虽然不用std::string,但也不进行内存分配与释放。追求的是高效能与地域无关性,结果就是这些这些函数比高阶数字转换函数快,其设计目的是进行完美的相互转换,比如将序列化的数字转化为字符表达,反过来也可以达到同样的目的。简单来说,就是同样的功能可以既可以用数字,也可以用字符来实现,且相互之间能进行高效率地转换。

2.1数字转字符串

        其实明白了低阶数字转换的原理与用途后,其使用方法是很简单的,看一下函数:

to_chars_result to_chars(char* first, char* last, IntegerT value, int base = 10);

简单做一下解释,first及last是指转换后的字符串指针指向,value是指任何有符号或无符号整型或字符(大家都清楚,在C/C++中,字符在计算机内部对应着相应的整数,如果此处不清楚,请恶补C语言基础),to_char_result定义如下:

struct to_chars_result {
    char* ptr;
    errc ec;
};

ptr指针在成功转换后所指向的是转换成功后的字符串,ec等于缺省结构化errc;如果不成功,则指向last,此时ec等于errc::value_too_large。老规矩,如果还是看不太明白,那就只有通过以下的例子来理解了:

import std;
using namespace std;
int main()
{
	const size_t BufferSize{ 50 };
	string out(BufferSize, ' ');
	auto result{ to_chars(out.data(),out.data() + out.size(),12345) };
	if (result.ec == errc{}) { println("{}", out); }
	return 0;
}

结果如下:

12345

还是很清晰的,多余的也没有什么好解释的了。多说一点另外的,就是C++中的结构化绑定(structured binding),可以将对result的声明及赋值部分的result直接修改为[ptr,error],效果是一样的。

import std;
using namespace std;
int main()
{
	const size_t BufferSize{ 50 };
	string out(BufferSize, ' ');
	auto [ptr, error]{ to_chars(out.data(),out.data() + out.size(),12345) };
	if (error == errc{}) { println("{}", out); }
	return 0;
}

同样的,浮点型的转换函数如下:

to_chars_result to_chars(char* first, char* last, FloatT value);
to_chars_result to_chars(char* first, char* last, FloatT value,
chars_format format);
to_chars_result to_chars(char* first, char* last, FloatT value,
chars_format format, int precision);

其中的value可以为float,double或者long double,format定义如下:

enum class chars_format {
	scientific,    // 格式: (-)d.ddde±dd
	fixed,         // 格式: (-)ddd.ddd
	hex,           // 格式: (-)h.hhhp±d (注意: 没有 0x!)
	general = fixed | scientific // 小数点前至少有一位数字的最简洁的表达方式.
};

precision精度没有指定的话,自动以给定格式给出最短的表达方式。给定精度的话,是指小数点后面的位数,看以下示例:

import std;
using namespace std;
int main()
{
	const size_t BufferSize{ 50 };
	double value{ 0.314567712345678901234567890 };
	string out(BufferSize, ' ');
	auto [ptr, error]{ to_chars(out.data(),out.data() + out.size(),value,chars_format::fixed) };
	if (error == errc{}) { println("{}", out); }
	return 0;
}

结果如下:

0.3145677123456789

大家可以根据以上说明进行学习和理解,也可以修改该示例,看一下chars_format各种设置情况下输出的不同,也可以设置一下precision精度,看输出都是什么样的。

        其实学习一门新的编程语言,基本功扎不扎实,就看你一开始有没有探究精神,是不是把你想到的都进行了尝试,多看看不同情形下的结果是什么样子的,你是不是真的学会了,在这一点上就真的见了真知,是真的已经掌握了精髓,还是浅尝辄止。

2.2字符串转数字

反过来就是将浮点型数字字符串转换为浮点型数字,其函数如下:

from_chars_result from_chars(const char* first, const char* last, IntegerT& value,int base = 10);
from_chars_result from_chars(const char* first, const char* last, FloatT& value,chars_format format = chars_format::general);

其中各项的意义,前面均有解释,如有不懂,请参阅前面。看一下from_chars_result的定义:

struct from_chars_result {
    const char* ptr;
    errc ec;
};

        ptr指针指向第一个没有被转换的字符,如果所有字符成功转换,则指向last,如果没有任何字符转换成功,则ptr与first一致,ec为errc::invalid_argument;如果解析出来的数字超过了数字所表达的范围,则ec为errc::result_out_of_range。还有一点需要注意的是,它不像高阶数字转换那样可以自动过滤前面的空格,这边不行,不过滤。

2.3、总结

        到这里,我们的低阶数字与字符串的相互转换就全部介绍完了,回到初心,低阶数字与字符串的设计就是为了在表达时更方便,用不同的方式提供给使用者,让我们最后用一个例子,看看是否达到了我们的目的,是否进行了完美的转换:

import std;
using namespace std;
int main()
{
	const size_t BufferSize{ 50 };
	double value1{ 0.314 };
	string out(BufferSize, ' ');
	auto [ptr1, error1]{ to_chars(out.data(),out.data() + out.size(),value1) };
	if (error1 == errc{}) { println("{}", out); }

	double value2;
	auto [ptr2, error2] {from_chars(out.data(), out.data() + out.size(), value2)};
	if (error2 == errc{}) {
		println("完美的相互转换");
	}
	else {
		println("不完美的相互转换?!?");
	}
	return 0;
}

看结果:

0.314
完美的相互转换

好了,目的达到了,本次课程也就结束了,祝大家学习愉快。

  • 14
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值