字符串转换成数字
常见的有三种方法:
1、利用C语言的函数atoi、atof等;
2、利用C++的流,std::stringstream;
3、利用std::stoi、std::stod等函数。
各有优劣,下面逐一分析。
为了方便,将std::stringstream的方法封装成一个模板函数,如下:
template<typename out_type, typename in_value>
out_type convert(const in_value & t){
std::stringstream stream;
stream << t;
out_type result;
stream >> result;
return result;
}
测试代码如下:
int _tmain(int argc, _TCHAR* argv[])
auto funPrint = [](const std::string& str){
std::cout << "-------------------------------------------" << std::endl;
std::cout << "原始字符串:" << str << std::endl;
std::cout << "aotf:" << atof(str.c_str()) << std::endl;
std::cout << "convert:" << convert<double>(str) << std::endl;
std::cout << "std::stod:" << std::stod(str) << std::endl;
std::string strValue("12.4ds52");
funPrint(strValue);
system("pause");
return 0;
}
这里为了后面的测试,将打印功能封装成了一个lambda表达式,执行结果如下:
三种方法,似乎没有区别,都是遇到第一个非合法字符就停止转换。继续,将主函数修改如下:
int _tmain(int argc, _TCHAR* argv[])
auto funPrint = [](const std::string& str){
std::cout << "-------------------------------------------" << std::endl;
std::cout << "原始字符串:" << str << std::endl;
std::cout << "aotf:" << atof(str.c_str()) << std::endl;
std::cout << "convert:" << convert<double>(str) << std::endl;
std::cout << "std::stod:" << std::stod(str) << std::endl;
std::string strValue("12.4ds52");
funPrint(strValue);
strValue = ("a23.4ds52");
funPrint(strValue);
system("pause");
return 0;
}
与上面相比,多了一次给strValue重新赋值,
新的值第一个字符就是非数字
,执行结果如下:
很不幸,程序崩溃!!!
从执行结果可以看出来,崩溃的乃是std::stod(str)这一句;另外,利用std::stringstream转换得到的数字为一个未初始化的双精度浮点数;似乎只有atof执行得比较靠谱。
std::stod系列函数(std::stoi、std::stof等),是可以避免让其崩溃的。当给定的字符串完全不能转换成数字,就会抛出一个
std::invalid_argument
的异常。据此,不但能避免崩溃,一定程度上还能判断字符串的合法性。修改代码如下:
int _tmain(int argc, _TCHAR* argv[])
auto funPrint = [](const std::string& str){
std::cout << "-------------------------------------------" << std::endl;
std::cout << "原始字符串:" << str << std::endl;
std::cout << "aotf:" << atof(str.c_str()) << std::endl;
std::cout << "convert:" << convert<double>(str) << std::endl;
std::cout << "std::stod:" << std::stod(str) << std::endl;
catch (std::invalid_argument&)
std::cout << "非法字符串!" << std::endl;
std::string strValue("12.4ds52");
funPrint(strValue);
strValue = ("a23.4ds52");
funPrint(strValue);
strValue = ("-.23.124.512");
funPrint(strValue);
strValue = ("--1.124");
funPrint(strValue);
system("pause");
return 0;
}
执行结果如下:
可以看到,四个字符串严格来说,都是非法的,但是只有第二个和第四个抛出了异常。
所以在实际项目中,需要根据具体情况,进行一些异常处理和判断,再选择合适的方式进行转换。
数字转换成字符串
与字符串转成数字差不多,也有三种方式:
1、sprintf_s函数(需要加上头文件 #include "stdio.h");
2、利用std::stringstream流;
3、std::to_string函数(宽字符可用std::to_wstring);
利用std::stringstream流,就是上面封装的convert函数。
sprintf_s函数为sprintf函数的安全版本,需要指定缓冲区大小。
示例代码如下:
int _tmain(int argc, _TCHAR* argv[])
auto funPrint_dTos = [](double dValue){
std::cout << "-------------------------------------------" << std::endl;
std::cout << "原始数字:" << dValue << std::endl;
char arr[216];
sprintf_s(arr, 216, "%f", dValue);
std::cout << "sprintf_s:" << arr << std::endl;
std::cout << "convert:" << convert<std::string>(dValue) << std::endl;
std::cout << "std::to_string:" << std::to_string(dValue) << std::endl;
funPrint_dTos(12.563);
system("pause");
return 0;
}
执行结果如下:
可以看到,sprintf_s和std::to_string都会保留精度,不够的会在小数末尾加上0。当然,sprintf_s可以指定保留的小数位数,将上述代码中的 sprintf_s(arr, 216, "%f", dValue)改为sprintf_s(arr, 216, "
%.2f
", dValue),执行结果如下:
至于std::to_string,似乎没有指定保留小数位数的办法,只能根据需求自己封装一个函数。
std::stringstream可以自动精确,去除末尾的0。
同样,也需要根据需求选择转换方式。