跳到主要内容

C++ 字符串转换

在C++编程中,字符串转换是一个非常常见的操作。无论是将数字转换为字符串用于显示,还是将字符串解析为数值进行计算,又或者是在不同字符串类型间互相转换,这些操作在实际开发中都经常遇到。本文将全面介绍C++中的字符串转换技术,帮助初学者掌握这一基础而重要的知识点。

字符串与基本类型的转换

数值类型转换为字符串

在C++中,将数值类型(如int、float、double等)转换为字符串有多种方法:

1. 使用 std::to_string 函数(C++11及以上)

cpp
#include <iostream>
#include <string>

int main() {
int num = 42;
std::string str = std::to_string(num);
std::cout << "整数转字符串: " << str << std::endl;

double pi = 3.14159;
std::string pi_str = std::to_string(pi);
std::cout << "浮点数转字符串: " << pi_str << std::endl;

return 0;
}

输出:

整数转字符串: 42
浮点数转字符串: 3.141590
备注

std::to_string 函数适用于所有数值类型,包括整数和浮点数,但对浮点数的格式控制能力有限。

2. 使用字符串流(更灵活的方式)

cpp
#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>

int main() {
// 使用字符串流转换整数
int num = 42;
std::stringstream ss1;
ss1 << num;
std::string str = ss1.str();
std::cout << "整数转字符串: " << str << std::endl;

// 使用字符串流转换浮点数并控制精度
double pi = 3.14159;
std::stringstream ss2;
ss2 << std::fixed << std::setprecision(2) << pi;
std::string pi_str = ss2.str();
std::cout << "浮点数转字符串(两位小数): " << pi_str << std::endl;

return 0;
}

输出:

整数转字符串: 42
浮点数转字符串(两位小数): 3.14

字符串转换为数值类型

1. 使用 C++11 标准库函数

cpp
#include <iostream>
#include <string>

int main() {
// 字符串转整数
std::string str_int = "42";
int num = std::stoi(str_int);
std::cout << "字符串转整数: " << num << " (原字符串: " << str_int << ")" << std::endl;

// 字符串转浮点数
std::string str_double = "3.14159";
double value = std::stod(str_double);
std::cout << "字符串转浮点数: " << value << " (原字符串: " << str_double << ")" << std::endl;

return 0;
}

输出:

字符串转整数: 42 (原字符串: 42)
字符串转浮点数: 3.14159 (原字符串: 3.14159)
提示

C++11提供的转换函数包括:

  • std::stoi - 转换为int
  • std::stol - 转换为long
  • std::stoll - 转换为long long
  • std::stof - 转换为float
  • std::stod - 转换为double
  • std::stold - 转换为long double

2. 使用字符串流

cpp
#include <iostream>
#include <string>
#include <sstream>

int main() {
std::string str_int = "42";
std::string str_double = "3.14159";

int num;
double value;

std::stringstream ss1(str_int);
ss1 >> num;
std::cout << "字符串转整数: " << num << std::endl;

std::stringstream ss2(str_double);
ss2 >> value;
std::cout << "字符串转浮点数: " << value << std::endl;

return 0;
}

输出:

字符串转整数: 42
字符串转浮点数: 3.14159

字符串之间的转换

1. C风格字符串与std::string的互相转换

cpp
#include <iostream>
#include <string>
#include <cstring>

int main() {
// C风格字符串转std::string
const char* c_str = "Hello, C++";
std::string cpp_str = c_str; // 直接赋值即可
std::cout << "C风格字符串转std::string: " << cpp_str << std::endl;

// std::string转C风格字符串
std::string message = "Welcome to C++";
const char* c_message = message.c_str();
std::cout << "std::string转C风格字符串: " << c_message << std::endl;

// 注意:使用c_str()得到的字符指针指向string内部的缓冲区
// 如果需要长期保存,应该复制一份
char* buffer = new char[message.length() + 1];
std::strcpy(buffer, message.c_str());
std::cout << "复制后的C风格字符串: " << buffer << std::endl;
delete[] buffer; // 记得释放内存

return 0;
}

输出:

C风格字符串转std::string: Hello, C++
std::string转C风格字符串: Welcome to C++
复制后的C风格字符串: Welcome to C++
警告

使用c_str()得到的C风格字符串指针指向std::string对象内部的缓冲区,如果原std::string对象被修改或销毁,该指针可能失效。如果需要长期保存,应该复制一份。

2. 字符串大小写转换

C++标准库没有提供直接的字符串大小写转换函数,但可以通过算法和字符转换函数实现:

cpp
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>

int main() {
std::string text = "Hello, C++ Programming!";
std::string upper_text = text;
std::string lower_text = text;

// 转换为大写
std::transform(upper_text.begin(), upper_text.end(), upper_text.begin(),
[](unsigned char c) { return std::toupper(c); });

// 转换为小写
std::transform(lower_text.begin(), lower_text.end(), lower_text.begin(),
[](unsigned char c) { return std::tolower(c); });

std::cout << "原始文本: " << text << std::endl;
std::cout << "转换为大写: " << upper_text << std::endl;
std::cout << "转换为小写: " << lower_text << std::endl;

return 0;
}

输出:

原始文本: Hello, C++ Programming!
转换为大写: HELLO, C++ PROGRAMMING!
转换为小写: hello, c++ programming!
备注

使用unsigned char作为lambda函数的参数类型是为了避免某些平台上对有符号字符处理可能出现的问题。

3. 字符串与宽字符串之间的转换

在某些情况下,需要在普通字符串和宽字符串(用于支持更广泛的字符集,如国际化文本)之间进行转换:

cpp
#include <iostream>
#include <string>
#include <codecvt>
#include <locale>

int main() {
// 普通字符串转宽字符串
std::string narrow = "Hello, 世界";
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::wstring wide = converter.from_bytes(narrow);

// 宽字符串转普通字符串
std::string narrow_back = converter.to_bytes(wide);

// 输出宽字符串
std::wcout << L"宽字符串: " << wide << std::endl;

// 输出转换回的普通字符串
std::cout << "转换回的字符串: " << narrow_back << std::endl;

return 0;
}
注意

注意:std::wstring_convert在C++17中被标记为弃用,但在很多环境中仍然可用。C++20以后可能需要使用其他方法进行Unicode转换。

实际应用案例

配置文件处理

在实际开发中,常常需要从配置文件中读取各种类型的数据。下面是一个简单的例子:

cpp
#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <sstream>

// 简单的配置文件读取类
class ConfigReader {
private:
std::map<std::string, std::string> configMap;

public:
bool loadFromFile(const std::string& filename) {
std::ifstream file(filename);
if (!file.is_open()) {
return false;
}

std::string line;
while (std::getline(file, line)) {
// 忽略注释和空行
if (line.empty() || line[0] == '#') {
continue;
}

size_t delimiterPos = line.find('=');
if (delimiterPos != std::string::npos) {
std::string key = line.substr(0, delimiterPos);
std::string value = line.substr(delimiterPos + 1);
configMap[key] = value;
}
}

file.close();
return true;
}

int getIntValue(const std::string& key, int defaultValue = 0) {
if (configMap.find(key) != configMap.end()) {
try {
return std::stoi(configMap[key]);
} catch (...) {
return defaultValue;
}
}
return defaultValue;
}

double getDoubleValue(const std::string& key, double defaultValue = 0.0) {
if (configMap.find(key) != configMap.end()) {
try {
return std::stod(configMap[key]);
} catch (...) {
return defaultValue;
}
}
return defaultValue;
}

std::string getStringValue(const std::string& key, const std::string& defaultValue = "") {
if (configMap.find(key) != configMap.end()) {
return configMap[key];
}
return defaultValue;
}
};

// 主函数演示
int main() {
// 假设有一个config.txt文件内容如下:
// port=8080
// max_connections=100
// server_name=MyTestServer
// timeout=5.5

ConfigReader config;
if (config.loadFromFile("config.txt")) {
int port = config.getIntValue("port");
int maxConn = config.getIntValue("max_connections");
std::string serverName = config.getStringValue("server_name");
double timeout = config.getDoubleValue("timeout");

std::cout << "服务器配置信息:" << std::endl;
std::cout << "端口: " << port << std::endl;
std::cout << "最大连接数: " << maxConn << std::endl;
std::cout << "服务器名称: " << serverName << std::endl;
std::cout << "超时时间: " << timeout << " 秒" << std::endl;
} else {
std::cout << "无法读取配置文件!" << std::endl;
}

return 0;
}

用户输入处理与验证

以下是一个处理用户输入并进行格式验证的例子:

cpp
#include <iostream>
#include <string>
#include <cctype>
#include <limits>

// 检查字符串是否是有效的整数
bool isValidInteger(const std::string& str) {
if (str.empty()) return false;

size_t i = 0;
if (str[0] == '-' || str[0] == '+') {
if (str.size() == 1) return false;
i = 1;
}

for (; i < str.size(); ++i) {
if (!std::isdigit(str[i])) {
return false;
}
}
return true;
}

// 检查字符串是否是有效的浮点数
bool isValidFloat(const std::string& str) {
if (str.empty()) return false;

size_t i = 0;
bool hasDecimal = false;

if (str[0] == '-' || str[0] == '+') {
if (str.size() == 1) return false;
i = 1;
}

for (; i < str.size(); ++i) {
if (str[i] == '.') {
if (hasDecimal) return false; // 不能有两个小数点
hasDecimal = true;
} else if (!std::isdigit(str[i])) {
return false;
}
}
return true;
}

int main() {
std::string input;
int intValue;
double doubleValue;

// 获取并验证整数输入
std::cout << "请输入一个整数: ";
std::getline(std::cin, input);

if (isValidInteger(input)) {
intValue = std::stoi(input);
std::cout << "您输入的整数是: " << intValue << std::endl;
} else {
std::cout << "无效的整数输入!" << std::endl;
}

// 获取并验证浮点数输入
std::cout << "请输入一个浮点数: ";
std::getline(std::cin, input);

if (isValidFloat(input)) {
doubleValue = std::stod(input);
std::cout << "您输入的浮点数是: " << doubleValue << std::endl;
} else {
std::cout << "无效的浮点数输入!" << std::endl;
}

return 0;
}

异常处理

在进行字符串转换时,如果转换失败,C++的转换函数会抛出异常。正确的异常处理可以使程序更加健壮:

cpp
#include <iostream>
#include <string>
#include <stdexcept>

int main() {
std::string validInt = "42";
std::string invalidInt = "42abc";
std::string outOfRange = "999999999999999999999999";

// 正常转换
try {
int num = std::stoi(validInt);
std::cout << "成功转换: " << num << std::endl;
} catch (const std::exception& e) {
std::cout << "转换失败: " << e.what() << std::endl;
}

// 无效格式
try {
int num = std::stoi(invalidInt);
std::cout << "成功转换: " << num << std::endl;
} catch (const std::invalid_argument& e) {
std::cout << "无效参数: " << e.what() << std::endl;
} catch (const std::exception& e) {
std::cout << "其他异常: " << e.what() << std::endl;
}

// 超出范围
try {
int num = std::stoi(outOfRange);
std::cout << "成功转换: " << num << std::endl;
} catch (const std::out_of_range& e) {
std::cout << "超出范围: " << e.what() << std::endl;
} catch (const std::exception& e) {
std::cout << "其他异常: " << e.what() << std::endl;
}

return 0;
}

输出(可能因编译器不同而略有差异):

成功转换: 42
无效参数: stoi: no conversion
超出范围: stoi: out of range

总结

本文介绍了C++中常见的字符串转换方法:

  1. 数值与字符串的互相转换

    • 使用std::to_string将数值转换为字符串
    • 使用std::stoistd::stod等函数将字符串转换为数值
    • 使用字符串流std::stringstream进行更灵活的转换
  2. 不同字符串类型间的转换

    • C风格字符串和std::string的互相转换
    • 字符串大小写转换
    • 普通字符串和宽字符串的转换
  3. 实际应用案例

    • 配置文件处理
    • 用户输入验证
  4. 异常处理

    • 处理无效输入导致的转换失败
    • 处理数值超出范围的情况

字符串转换是编程中极其常见的操作,掌握这些技术可以让你更高效地处理文本数据,并确保程序的健壮性和可靠性。

练习

  1. 编写一个函数,将给定的温度值在摄氏度和华氏度之间转换,使用字符串作为输入和输出。
  2. 实现一个简单的计算器程序,从命令行读取如"5 + 3"或"10 * 2"这样的表达式,并计算结果。
  3. 编写一个程序,读取一个包含数字的文本文件,计算这些数字的总和和平均值。
  4. 创建一个函数,将罗马数字(如"XIV"、"MCMXCIV")转换为阿拉伯数字。
  5. 实现一个URL解析器,将URL字符串分解为协议、域名、路径等组件。

通过这些练习,你可以更好地掌握C++中的字符串转换技术,为更复杂的编程挑战做好准备。

提示

记住,对于字符串转换来说,异常处理和输入验证非常重要,它们可以防止程序在面对无效数据时崩溃。