C/C++中的字符串分割(z)

本文介绍了一种在C语言中高效地对字符串进行分割的方法,使用strtok()函数替代了传统MFC和std::string中find()+Mid()或substr()的方法。这种方法避免了对每个子字符串单独分配内存,从而减少了内存碎片并提高了效率。
字符串按照特定字符进行分割是编程时候经常要用到方法

MFC中CString 和std::string 常可以用 find() + Mid() 的方法来实现

CString实现:

Cpp代码
inline static void split(CString src, CString token, vector<CString>& vect)
{
int nend=0;
int nbegin=0;
while(nend != -1)
{
nend = src.Find(token, nbegin);
if(nend == -1)
vect.push_back(src.Mid(nbegin, src.GetLength()-nbegin));
else
vect.push_back(src.Mid(nbegin, nend-nbegin));
nbegin = nend + 1;
}
}
std::string实现

Cpp代码
inline static void split(std::string src, std::string token, vector<std::string>& vect)
{
int nend=0;
int nbegin=0;
while(nend != -1)
{
nend = src.find_first_of(token, nbegin);
if(nend == -1)
vect.push_back(src.substr(nbegin, src.length()-nbegin));
else
vect.push_back(src.substr(nbegin, nend-nbegin));
nbegin = nend + 1;
}
}
上面2个例子中,分割出来字符串都是重新分配了内存的。

例如CString中Mid()函数就会

CString dest;
AllocCopy(dest, nCount, nFirst, 0); //这个地方将会为 dest分配内存空间
return dest;

所以在负荷较高的运行环境下会频繁的分配小块内存和释放小块内存,比较容易生产内存碎片,而且效率也不高。

潜意识中喜欢追求底层细节,让我想了解 在C语言中 char * 到底是怎么实现分割的?

果不其然C语言中的 strtok() 函数能够实现字符串的分割而且效率超高,不需要对分割后的字符串进行内存分配,而只是将被分割字 符中的 分隔符 ( token ) 以\0代替。而大家都知道 字符串都是以\0结尾的,所以这样就达到了将一个整串分割成多个字符串的目的。

char * 实现:

Cpp代码
inline static void Split(const char* content, const char* token, vector<std::string>& vect)
{
if(content == NULL)
return;
int len = strlen(content);
if(len <= 0)
return;
char* pBuf =(char*)malloc(len+1);
strcpy(pBuf , content);
char* str = strtok(pBuf , token);
while(str != NULL)
{
vect.push_back(str);
str = strtok(NULL, token);
}
free(pBuf);
}
<think>我们有一个任务:在C++中将字符串中的字母和数字部分分开。例如,对于输入字符串 "abc123def456",我们希望得到两个字符串:一个只包含字母("abcdef"),另一个只包含数字("123456")。 我们可以使用循环遍历字符串的每个字符,然后根据字符类型(字母或数字)将其分别添加到两个不同的字符串中。 在C++中,我们可以使用标准库函数来判断字符类型: - 使用 `std::isalpha` 检查字符是否为字母。 - 使用 `std::isdigit` 检查字符是否为数字。 注意:这些函数在头文件 `<cctype>` 中声明。 步骤: 1. 定义两个字符串,一个用于存储字母(letters),另一个用于存储数字(digits)。 2. 遍历输入字符串的每个字符。 3. 如果字符是字母,则添加到letters字符串。 4. 如果字符是数字,则添加到digits字符串。 5. 忽略其他字符(如果需要,也可以根据需求处理)。 示例代码: ```cpp #include <iostream> #include <string> #include <cctype> // 用于 isalpha 和 isdigit int main() { std::string input = "abc123def456"; std::string letters; std::string digits; for (char c : input) { if (std::isalpha(c)) { letters += c; } else if (std::isdigit(c)) { digits += c; } // 其他字符忽略 } std::cout << "Letters: " << letters << std::endl; std::cout << "Digits: " << digits << std::endl; return 0; } ``` 输出: ``` Letters: abcdef Digits: 123456 ``` 注意:`std::isalpha` 和 `std::isdigit` 函数是C标准库函数,在C++中位于`<cctype>`头文件中。它们接受一个int类型的参数,但我们可以传入char类型,因为char可以提升为int。返回值为非零表示真,零表示假。 另外,如果字符串中包含非字母和数字的字符(如空格、标点等),上述代码会忽略它们。如果需求变化,需要保留其他字符,可以相应调整。 如果希望将原字符串分割成多个部分(例如,保留连续的数字或字母序列),那么可能需要使用不同的方法(比如使用正则表达式或状态机),但根据问题,我们只需要分开字母和数字,所以上述方法即可。 如果输入字符串很大,我们可以预先为letters和digits保留足够的空间,以避免多次重新分配。例如: ```cpp letters.reserve(input.size()); digits.reserve(input.size()); ``` 但是,实际中如果大部分字符都是字母或数字中的一种,那么另一个字符串可能会浪费预留的空间。因此,是否预留空间取决于具体情况。 如果需求是分割字符串中的连续字母和数字序列(例如,将"abc123def"分割成["abc", "123", "def"]),那么我们可以使用如下方法: 方法二:提取连续序列 我们可以遍历字符串,当当前字符的类型(字母、数字或其他)与前一个不同时,就开启一个新的序列。 示例代码: ```cpp #include <iostream> #include <string> #include <vector> #include <cctype> int main() { std::string input = "abc123def456"; std::vector<std::string> parts; if (input.empty()) { // 处理空字符串 return 0; } // 初始化第一个子串,从第一个字符开始 std::string current = ""; current += input[0]; char lastType = std::isalpha(input[0]) ? 'a' : (std::isdigit(input[0]) ? 'd' : 'o'); for (size_t i = 1; i < input.size(); i++) { char c = input[i]; char currentType = std::isalpha(c) ? 'a' : (std::isdigit(c) ? 'd' : 'o'); // 如果当前字符类型与上一个相同,或者都是其他类型('o'),则继续当前子串 if (currentType == lastType || (lastType == 'o' && currentType == 'o')) { current += c; } else { // 类型变化,将当前子串加入结果,并开始新的子串 parts.push_back(current); current = std::string(1, c); // 以当前字符开始新子串 lastType = currentType; } } // 加入最后一个子串 if (!current.empty()) { parts.push_back(current); } // 输出结果 for (const auto& part : parts) { std::cout << part << std::endl; } return 0; } ``` 但是,根据问题描述,我们只需要分开字母和数字,并不需要保留连续序列。所以第一种方法更符合要求。 因此,我们选择第一种方法作为解答。 相关问题: 1. 在C++中如何判断一个字符是字母还是数字? 2. 如何忽略字符串中的非字母数字字符? 3. 如何将字符串中的字母和数字分别提取并存储到两个新字符串中?</think>在 C++ 中,将字符串中的字母和数字分离可以通过遍历字符串并使用字符分类函数实现。以下是完整解决方案: ### 方法 1:使用字符分类函数(推荐) ```cpp #include <iostream> #include <string> #include <cctype> // 包含 isalpha 和 isdigit int main() { std::string input = "abc123def456"; std::string letters; std::string numbers; for (char c : input) { if (std::isalpha(c)) { // 检查是否为字母 letters += c; } else if (std::isdigit(c)) { // 检查是否为数字 numbers += c; } // 忽略其他字符(如标点符号) } std::cout << "字母部分: " << letters << "\n"; std::cout << "数字部分: " << numbers << std::endl; return 0; } ``` **输出**: ``` 字母部分: abcdef 数字部分: 123456 ``` ### 方法 2:使用范围循环和 lambda 表达式(C++11) ```cpp #include <iostream> #include <string> #include <cctype> #include <algorithm> int main() { std::string input = "Hello123World456"; std::string letters; std::string numbers; // 使用 copy_if 算法分离字符 std::copy_if(input.begin(), input.end(), std::back_inserter(letters), [](char c) { return std::isalpha(c); }); std::copy_if(input.begin(), input.end(), std::back_inserter(numbers), [](char c) { return std::isdigit(c); }); std::cout << "字母: " << letters << "\n"; std::cout << "数字: " << numbers << std::endl; return 0; } ``` ### 关键点说明 1. **字符分类函数**: - `std::isalpha()`:检测字符是否为字母(A-Z, a-z) - `std::isdigit()`:检测字符是否为数字(0-9) - 需要包含头文件 `<cctype>` 2. **特殊字符处理**: - 非字母数字字符(如空格、标点)会被自动忽略 - 如需保留其他字符,可添加额外判断条件 3. **性能优化**: ```cpp // 预分配内存避免重复分配 letters.reserve(input.size()); numbers.reserve(input.size()); ``` ### 注意事项 - 如果字符串包含 Unicode 字符(如中文),需使用 `<locale>` 库或第三方库(如 ICU) - 对于带符号数字(如 "-123"),需要额外逻辑处理负号 - 大小写敏感:`isalpha()` 不区分大小写,如需保留大小写需直接存储原字符 > 示例参考:字符分类函数在 C++ 标准库中的实现基于本地化设置,可正确处理 ASCII 字符集[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值