首页 > 应用开发 > IT综合 > C++字符与字符串处理函数深度解析与应用实践
《C++字符与字符串处理函数深度解析与应用实践》
字符和字符串处理是编程中的基础操作,C++提供了从C语言继承的字符函数库和现代化的string类。理解这些工具的特性和正确使用方式,对编写高效、安全的文本处理程序至关重要。
**C风格字符处理函数**
```cpp
#include <cctype> // 字符分类和转换函数
#include <iostream>
void characterFunctionsDemo() {
char ch = 'A';
// 1. 字符分类函数
std::cout << "字符分类测试:" << std::endl;
std::cout << "isalpha('A'): " << isalpha('A') << std::endl; // 字母
std::cout << "isdigit('9'): " << isdigit('9') << std::endl; // 数字
std::cout << "isalnum('a'): " << isalnum('a') << std::endl; // 字母或数字
std::cout << "isspace(' '): " << isspace(' ') << std::endl; // 空白字符
std::cout << "islower('a'): " << islower('a') << std::endl; // 小写字母
std::cout << "isupper('A'): " << isupper('A') << std::endl; // 大写字母
std::cout << "ispunct('!'): " << ispunct('!') << std::endl; // 标点符号
std::cout << "isxdigit('F'): " << isxdigit('F') << std::endl; // 十六进制数字
// 2. 字符转换函数
std::cout << "\n字符转换测试:" << std::endl;
char lower = 'a';
char upper = 'Z';
std::cout << "toupper('a'): " << static_cast<char>(toupper(lower)) << std::endl;
std::cout << "tolower('Z'): " << static_cast<char>(tolower(upper)) << std::endl;
// 注意:这些函数接收int参数,返回int结果
// 处理前应确保字符在unsigned char范围内
char testChar = -1; // 潜在问题
if (testChar >= 0 && testChar <= 127) {
// 安全使用
bool result = isalpha(testChar);
}
// 3. 实用字符处理函数
void processString(const char* str) {
for (int i = 0; str[i] != '\0'; i++) {
if (isalpha(str[i])) {
if (isupper(str[i])) {
std::cout << "大写字母: " << str[i] << std::endl;
} else {
std::cout << "小写字母: " << str[i] << std::endl;
}
} else if (isdigit(str[i])) {
std::cout << "数字: " << str[i] << std::endl;
} else if (isspace(str[i])) {
std::cout << "空格" << std::endl;
}
}
}
}
```
**C风格字符串函数**
```cpp
#include <cstring> // C风格字符串函数
void cStringFunctions() {
const int BUFFER_SIZE = 100;
// 1. 字符串长度
const char* str1 = "Hello, World!";
size_t len = strlen(str1);
std::cout << "字符串长度: " << len << std::endl;
// 2. 字符串复制
char dest1[BUFFER_SIZE];
strcpy(dest1, "Hello"); // 基本复制
std::cout << "strcpy结果: " << dest1 << std::endl;
// 安全版本:strncpy
char dest2[BUFFER_SIZE];
strncpy(dest2, "Hello, World!", BUFFER_SIZE - 1);
dest2[BUFFER_SIZE - 1] = '\0'; // 确保终止符
std::cout << "strncpy结果: " << dest2 << std::endl;
// 3. 字符串连接
char buffer[BUFFER_SIZE] = "Hello";
strcat(buffer, ", World!"); // 连接
std::cout << "strcat结果: " << buffer << std::endl;
// 安全版本:strncat
char buffer2[BUFFER_SIZE] = "Hello";
strncat(buffer2, ", Universe!", BUFFER_SIZE - strlen(buffer2) - 1);
std::cout << "strncat结果: " << buffer2 << std::endl;
// 4. 字符串比较
const char* str2 = "apple";
const char* str3 = "banana";
const char* str4 = "apple";
int cmp1 = strcmp(str2, str3); // 负值:str2 < str3
int cmp2 = strcmp(str2, str4); // 0:相等
int cmp3 = strcmp(str3, str2); // 正值:str3 > str2
std::cout << "\n字符串比较结果: " << cmp1 << ", " << cmp2 << ", " << cmp3 << std::endl;
// 不区分大小写比较
const char* str5 = "Hello";
const char* str6 = "hello";
int cmp4 = strcasecmp(str5, str6); // 0:忽略大小写时相等
// 5. 字符串查找
const char* text = "The quick brown fox jumps over the lazy dog";
const char* word = "fox";
// 查找子串
char* found = strstr(text, word);
if (found) {
std::cout << "找到子串 '" << word << "' 在位置: " << (found - text) << std::endl;
}
// 查找字符
char* charFound = strchr(text, 'q');
if (charFound) {
std::cout << "找到字符 'q' 在位置: " << (charFound - text) << std::endl;
}
// 反向查找字符
char* rcharFound = strrchr(text, 'o');
if (rcharFound) {
std::cout << "从后向前找到字符 'o' 在位置: " << (rcharFound - text) << std::endl;
}
// 6. 字符串分割
char csv[] = "apple,banana,cherry,date";
char* token = strtok(csv, ",");
std::cout << "\n字符串分割结果: " << std::endl;
while (token != nullptr) {
std::cout << token << std::endl;
token = strtok(nullptr, ",");
}
}
```
**安全的C字符串函数**
```cpp
#include <cstring>
class SafeStringOperations {
public:
// 安全的字符串复制
static bool safe_strcpy(char* dest, size_t destSize, const char* src) {
if (dest == nullptr || src == nullptr || destSize == 0) {
return false;
}
size_t srcLen = strlen(src);
if (srcLen >= destSize) {
return false; // 目标缓冲区太小
}
strcpy(dest, src);
return true;
}
// 安全的字符串连接
static bool safe_strcat(char* dest, size_t destSize, const char* src) {
if (dest == nullptr || src == nullptr || destSize == 0) {
return false;
}
size_t destLen = strlen(dest);
size_t srcLen = strlen(src);
if (destLen + srcLen >= destSize) {
return false; // 缓冲区溢出风险
}
strcat(dest, src);
return true;
}
// 安全的字符串格式化
static bool safe_sprintf(char* dest, size_t destSize, const char* format, ...) {
if (dest == nullptr || format == nullptr || destSize == 0) {
return false;
}
va_list args;
va_start(args, format);
// 使用vsnprintf检查长度
int needed = vsnprintf(dest, destSize, format, args);
va_end(args);
return needed >= 0 && static_cast<size_t>(needed) < destSize;
}
// 字符串复制并返回实际复制长度
static size_t strlcpy(char* dest, const char* src, size_t size) {
if (size == 0) {
return strlen(src);
}
size_t srcLen = strlen(src);
size_t copyLen = (srcLen < size - 1) ? srcLen : size - 1;
memcpy(dest, src, copyLen);
dest[copyLen] = '\0';
return srcLen;
}
// 字符串连接并返回实际连接后长度
static size_t strlcat(char* dest, const char* src, size_t size) {
size_t destLen = strlen(dest);
if (destLen >= size) {
return destLen + strlen(src);
}
return destLen + strlcpy(dest + destLen, src, size - destLen);
}
};
```
**C++字符串类的基本操作**
```cpp
#include <string>
#include <sstream>
#include <algorithm>
void stringClassDemo() {
// 1. 字符串构造和初始化
std::string str1; // 空字符串
std::string str2 = "Hello"; // 从C字符串构造
std::string str3("World"); // 构造函数
std::string str4(10, '*'); // 10个'*'
std::string str5(str2); // 拷贝构造
std::string str6 = str2 + ", " + str3; // 连接
// C++11初始化列表
std::string str7{'H', 'e', 'l', 'l', 'o'};
// 2. 字符串赋值和连接
std::string s = "Start";
s = "New Value"; // 赋值
s.assign("Assigned Value"); // assign方法
s += " appended"; // 追加
s.append(" more"); // append方法
s.push_back('!'); // 添加单个字符
// 3. 字符串访问
std::string text = "Hello, World!";
std::cout << "原始字符串: " << text << std::endl;
std::cout << "长度: " << text.length() << std::endl;
std::cout << "大小: " << text.size() << std::endl;
std::cout << "容量: " << text.capacity() << std::endl;
std::cout << "是否空: " << text.empty() << std::endl;
// 访问字符
std::cout << "第一个字符: " << text[0] << std::endl;
std::cout << "第二个字符: " << text.at(1) << std::endl;
std::cout << "最后一个字符: " << text.back() << std::endl;
std::cout << "第一个字符: " << text.front() << std::endl;
// 修改字符
text[7] = 'w'; // World -> world
std::cout << "修改后: " << text << std::endl;
// 4. 字符串比较
std::string a = "apple";
std::string b = "banana";
if (a == b) {
std::cout << "相等" << std::endl;
} else if (a < b) {
std::cout << a << " < " << b << std::endl;
} else {
std::cout << a << " > " << b << std::endl;
}
// compare方法
int result = a.compare(b);
std::cout << "compare结果: " << result << std::endl;
// 5. 字符串查找
std::string sentence = "The quick brown fox jumps over the lazy dog";
// 查找子串
size_t pos = sentence.find("fox");
if (pos != std::string::npos) {
std::cout << "找到'fox'在位置: " << pos << std::endl;
}
// 反向查找
pos = sentence.rfind("the");
if (pos != std::string::npos) {
std::cout << "从后向前找到'the'在位置: " << pos << std::endl;
}
// 查找字符集合中的任意字符
pos = sentence.find_first_of("aeiou");
std::cout << "第一个元音字母位置: " << pos << std::endl;
pos = sentence.find_last_of("aeiou");
std::cout << "最后一个元音字母位置: " << pos << std::endl;
}
```
**字符串修改与操作**
```cpp
void stringModifications() {
// 1. 子串操作
std::string full = "Hello, World!";
// 提取子串
std::string sub = full.substr(7, 5); // 从位置7开始,长度5
std::cout << "子串: " << sub << std::endl; // "World"
// 2. 插入操作
std::string str = "Hello World!";
str.insert(6, "Beautiful ");
std::cout << "插入后: " << str << std::endl;
// 3. 删除操作
str.erase(6, 10); // 从位置6开始删除10个字符
std::cout << "删除后: " << str << std::endl;
// 4. 替换操作
str.replace(0, 5, "Hi"); // 替换前5个字符
std::cout << "替换后: " << str << std::endl;
// 5. 大小写转换
std::string mixed = "Hello World!";
// 转换为大写
std::string upper = mixed;
std::transform(upper.begin(), upper.end(), upper.begin(), ::toupper);
<"ovo.j9k5.org.cn"><"bvd.j9k5.org.cn"><"tab.j9k5.org.cn">
std::cout << "大写: " << upper << std::endl;
// 转换为小写
std::string lower = mixed;
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
std::cout << "小写: " << lower << std::endl;
// 6. 去除空白字符
std::string withSpaces = " Hello World! ";
// 去除左侧空白
size_t start = withSpaces.find_first_not_of(" \t\n\r");
if (start != std::string::npos) {
withSpaces = withSpaces.substr(start);
}
// 去除右侧空白
size_t end = withSpaces.find_last_not_of(" \t\n\r");
if (end != std::string::npos) {
withSpaces = withSpaces.substr(0, end + 1);
}
std::cout << "去除空白后: '" << withSpaces << "'" << std::endl;
}
```
**字符串流处理**
```cpp
#include <sstream>
#include <vector>
void stringStreamDemo() {
// 1. 字符串分割(使用stringstream)
std::string csv = "apple,banana,cherry,date";
std::stringstream ss(csv);
std::string token;
std::vector<std::string> fruits;
while (std::getline(ss, token, ',')) {
fruits.push_back(token);
}
std::cout << "分割结果: ";
for (const auto& fruit : fruits) {
std::cout << fruit << " ";
}
std::cout << std::endl;
// 2. 字符串转换为数字
std::string numStr = "123.45";
// 转换为整数
std::stringstream ss1(numStr);
int intVal;
ss1 >> intVal;
std::cout << "整数: " << intVal << std::endl;
// 转换为浮点数
std::stringstream ss2(numStr);
double doubleVal;
ss2 >> doubleVal;
std::cout << "浮点数: " << doubleVal << std::endl;
// 3. 数字转换为字符串
int number = 42;
std::stringstream ss3;
ss3 << number;
std::string numString = ss3.str();
std::cout << "转换后的字符串: " << numString << std::endl;
// 使用to_string(C++11)
double pi = 3.14159;
std::string piStr = std::to_string(pi);
std::cout << "圆周率字符串: " << piStr << std::endl;
// 4. 复杂格式化
std::stringstream formatted;
formatted << "姓名: " << "张三" << ", "
<< "年龄: " << 25 << ", "
<< "身高: " << std::fixed << std::setprecision(2) << 175.5 << "cm";
std::cout << "格式化结果: " << formatted.str() << std::endl;
// 5. 字符串拼接
std::stringstream builder;
builder << "Part1" << " " << "Part2" << " " << 100;
std::string result = builder.str();
std::cout << "拼接结果: " << result << std::endl;
}
```
**宽字符和多字节字符串**
```cpp
#include <cwchar>
#include <locale>
void wideCharDemo() {
// 1. 宽字符字符串
const wchar_t* wideStr = L"宽字符字符串";
std::wcout << L"宽字符: " << wideStr << std::endl;
// 设置本地化,支持中文输出
std::locale::global(std::locale(""));
std::wcout.imbue(std::locale());
// 2. 宽字符操作
wchar_t wch = L'中';
std::wcout << L"宽字符: " << wch << std::endl;
// 宽字符分类函数
std::wcout << L"iswalpha(L'A'): " << iswalpha(L'A') << std::endl;
std::wcout << L"iswdigit(L'9'): " << iswdigit(L'9') << std::endl;
// 3. 宽字符串操作
wchar_t wideBuffer[100];
wcscpy(wideBuffer, L"你好");
wcscat(wideBuffer, L", 世界!");
std::wcout << L"宽字符串: " << wideBuffer << std::endl;
// 4. 多字节和宽字符转换
const char* mbStr = "你好,世界!";
wchar_t wStr[100];
// 多字节转宽字符
size_t converted = mbstowcs(wStr, mbStr, 100);
if (converted != static_cast<size_t>(-1)) {
std::wcout << L"转换后: " << wStr << std::endl;
}
// 宽字符转多字节
char mbBuffer[100];
wcstombs(mbBuffer, wStr, 100);
std::cout << "转回多字节: " << mbBuffer << std::endl;
// 5. C++宽字符串类
std::wstring wstr = L"宽字符串类";
wstr += L" - 支持中文";
std::wcout << L"wstring: " << wstr << std::endl;
}
```
**正则表达式处理**
```cpp
#include <regex>
void regexDemo() {
// 1. 基本正则表达式匹配
std::string text = "我的电话是: 138-1234-5678,邮箱: user@example.com";
// 匹配电话号码
std::regex phonePattern(R"(\d{3}-\d{4}-\d{4})");
std::smatch phoneMatch;
if (std::regex_search(text, phoneMatch, phonePattern)) {
std::cout << "找到电话号码: " << phoneMatch.str() << std::endl;
}
// 2. 匹配邮箱地址
std::regex emailPattern(R"([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})");
std::sregex_iterator it(text.begin(), text.end(), emailPattern);
std::sregex_iterator end;
std::cout << "找到邮箱地址: ";
for (; it != end; ++it) {
std::cout << it->str() << " ";
}
std::cout << std::endl;
// 3. 正则表达式替换
std::string html = "<p>Hello</p><br><div>World</div>";
std::regex tagPattern(R"(<[^>]*>)");
// 移除所有HTML标签
std::string plain = std::regex_replace(html, tagPattern, "");
std::cout << "纯文本: " << plain << std::endl;
// 4. 验证字符串格式
std::string date = "2024-01-15";
std::regex datePattern(R"(\d{4}-\d{2}-\d{2})");
if (std::regex_match(date, datePattern)) {
std::cout << "日期格式正确: " << date << std::endl;
} else {
std::cout << "日期格式错误" << std::endl;
}
// 5. 分组捕获
std::string logEntry = "2024-01-15 14:30:25 ERROR Database connection failed";
std::regex logPattern(R"((\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) (\w+) (.+))");
std::smatch logMatch;
if (std::regex_match(logEntry, logMatch, logPattern)) {
std::cout << "日志解析结果:" << std::endl;
std::cout << "日期: " << logMatch[1] << std::endl;
std::cout << "时间: " << logMatch[2] << std::endl;
std::cout << "级别: " << logMatch[3] << std::endl;
std::cout << "消息: " << logMatch[4] << std::endl;
}
}
```
**字符串编码与转换**
```cpp
#include <codecvt>
#include <locale>
class StringEncoding {
public:
// UTF-8 转 UTF-16
static std::u16string utf8_to_utf16(const std::string& utf8) {
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter;
return converter.from_bytes(utf8);
}<"cec.j9k5.org.cn"><"vds.j9k5.org.cn"><"kfc.j9k5.org.cn">
// UTF-16 转 UTF-8
static std::string utf16_to_utf8(const std::u16string& utf16) {
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter;
return converter.to_bytes(utf16);
}
// UTF-8 转 UTF-32
static std::u32string utf8_to_utf32(const std::string& utf8) {
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter;
return converter.from_bytes(utf8);
}
// 字符串编码检测(简化版)
static std::string detectEncoding(const std::string& str) {
// 简单检测UTF-8 BOM
if (str.size() >= 3 &&
static_cast<unsigned char>(str[0]) == 0xEF &&
static_cast<unsigned char>(str[1]) == 0xBB &&
static_cast<unsigned char>(str[2]) == 0xBF) {
return "UTF-8 with BOM";
}
// 统计ASCII范围外的字节
size_t nonAscii = 0;
for (unsigned char c : str) {
if (c > 127) nonAscii++;
}
if (nonAscii > str.size() * 0.1) { // 超过10%非ASCII字符
return "可能为UTF-8或其它编码";
}
return "ASCII或扩展ASCII";
}
// URL编码
static std::string urlEncode(const std::string& value) {
std::ostringstream escaped;
escaped.fill('0');
escaped << std::hex;
for (char c : value) {
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
escaped << c;
} else {
escaped << '%' << std::setw(2) << int(static_cast<unsigned char>(c));
}
}
return escaped.str();
}
// URL解码
static std::string urlDecode(const std::string& value) {
std::ostringstream decoded;
for (size_t i = 0; i < value.length(); ++i) {
if (value[i] == '%' && i + 2 < value.length()) {
std::string hex = value.substr(i + 1, 2);
char decodedChar = static_cast<char>(strtol(hex.c_str(), nullptr, 16));
decoded << decodedChar;
i += 2;
} else if (value[i] == '+') {
decoded << ' ';
} else {
decoded << value[i];
}
}
return decoded.str();
}
};
```
**性能优化与实践**
```cpp
class StringPerformance {
public:
static void benchmarkConcatenation() {
const int ITERATIONS = 10000;
std::cout << "字符串连接性能测试:" << std::endl;
std::cout << "=" << 40 << std::endl;
// 1. 使用+运算符
auto start = std::chrono::high_resolution_clock::now();
std::string result1;
for (int i = 0; i < ITERATIONS; i++) {
result1 += "test";
}
auto end = std::chrono::high_resolution_clock::now();
auto time1 = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "使用+运算符: " << time1.count() << "μs" << std::endl;
// 2. 使用append
start = std::chrono::high_resolution_clock::now();
std::string result2;
for (int i = 0; i < ITERATIONS; i++) {
result2.append("test");
}
end = std::chrono::high_resolution_clock::now();
auto time2 = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "使用append: " << time2.count() << "μs" << std::endl;
// 3. 预分配内存
start = std::chrono::high_resolution_clock::now();
std::string result3;
result3.reserve(ITERATIONS * 4); // 预分配足够空间
for (int i = 0; i < ITERATIONS; i++) {
result3 += "test";
}
end = std::chrono::high_resolution_clock::now();
auto time3 = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "预分配内存: " << time3.count() << "μs" << std::endl;
// 4. 使用stringstream
start = std::chrono::high_resolution_clock::now();
std::stringstream ss;
for (int i = 0; i < ITERATIONS; i++) {
ss << "test";
}
std::string result4 = ss.str();
end = std::chrono::high_resolution_clock::now();
auto time4 = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "使用stringstream: " << time4.count() << "μs" << std::endl;
}
static void optimizeTips() {
std::cout << "\n字符串优化建议:" << std::endl;
std::cout << "=" << 40 << std::endl;
std::cout << "1. 对于大量字符串连接,使用ostringstream" << std::endl;
std::cout << "2. 预分配字符串内存,避免多次重新分配" << std::endl;
std::cout << "3. 使用string_view(C++17)避免不必要的拷贝" << std::endl;
std::cout << "4. 避免在循环中使用临时字符串" << std::endl;
std::cout << "5. 使用移动语义转移字符串所有权" << std::endl;
std::cout << "6. 对于只读字符串,使用const引用传递" << std::endl;
std::cout << "7. 考虑使用字符数组处理固定长度字符串" << std::endl;
std::cout << "8. 批量处理字符串操作,减少函数调用" << std::endl;
}
// 使用string_view(C++17)
static void stringViewDemo() {
#if __cplusplus >= 201703L
std::string longText = "这是一个非常长的文本字符串";
std::string_view view(longText);
// 获取子视图,不产生拷贝
std::string_view subview = view.substr(2, 10);
std::cout << "子视图: " << subview << std::endl;
// 字符串视图操作
std::cout << "大小: " << subview.size() << std::endl;
std::cout << "是否空: " << subview.empty() << std::endl;
std::cout << "第一个字符: " << subview.front() << std::endl;
std::cout << "最后一个字符: " << subview.back() << std::endl;
#endif
}
};
```
**最佳实践总结**
1. **安全性优先**:
- 使用安全的字符串函数版本
- 检查缓冲区边界
- 验证输入字符串
2. **编码处理**:
- 明确字符串编码(UTF-8、GBK等)
- 使用统一的内部编码
- 正确处理多字节字符
3. **性能考虑**:
- 避免不必要的字符串拷贝
- 预分配足够内存
- 使用合适的字符串操作
4. **错误处理**:
- 检查函数返回值
- 处理空指针和空字符串
- 记录和处理转换错误
5. **现代C++特性**:
- 优先使用std::string而非C字符串
- 使用string_view避免拷贝
- 利用移动语义优化性能
- 使用正则表达式处理复杂模式
掌握字符和字符串处理是编程基础,正确的使用方式直接影响程序的稳定性、安全性和性能。通过理解各种字符串函数的特性和适用场景,开发者可以编写出更健壮的文本处理代码。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3109403/ ,如需转载,请注明出处,否则将追究法律责任。