/****************************************************************************** 函数名称:extractBetweenTildes 功能说明:将vector<NXString>数组中含有“~”的字符拆分,选择“~”后的的字符串 或者两个“~”之间的字符串 返 回 值:void 参 数:vector<NXString>* nxStrsList 作 者: LuoPengyu 日 期: 2025/3/18 ******************************************************************************/ void StdCategory::extractBetweenTildes(vector<NXString>* nxStrsList) { const char cDelim = '~'; const int nBufSize = 200; char tempStr[nBufSize]; for(size_t i = 0; i < nxStrsList->size(); i++) { sprintf_s(tempStr,nBufSize,"%s",(*nxStrsList)[i].getLocaleText()); // 查找最后一个 ~ char* lastDelim = strrchr(tempStr,cDelim); if(!lastDelim) { continue; // 无 ~ 则跳过 } // 尝试查找倒数第二个 ~ *lastDelim = '\0'; // 截断到最后一个 ~ 前 char* secondLastDelim = strrchr(tempStr,cDelim); // 根据是否存在倒数第二个 ~ 决定目标内容 char* target = (secondLastDelim != nullptr) ? (secondLastDelim + 1) : (lastDelim + 1); // 去除前后空白(原逻辑) while(*target == ' ' || *target == '\t') target++; char* end = target + strlen(target) - 1; while(end >= target && (*end == ' ' || *end == '\t')) end--; *(end + 1) = '\0'; // 回写结果 (*nxStrsList)[i] = target; } }修改为有1个~取最后一个~后的字符串,有2个取第1,2两个~的字符串,有3个第2,3个~间的字符串
时间: 2025-04-11 21:13:53 浏览: 47
<think>好的,我现在需要修改这个extractBetweenTildes函数,让它满足新的需求。用户的要求是:当字符串中有1个波浪线时,取最后一个波浪线后的内容;如果有2个波浪线,取第一个和第二个之间的内容;如果有3个或更多,取第二和第三个之间的内容。首先,我得仔细理解原来的代码逻辑。
原来的函数逻辑是,无论有多少个波浪线,都找到最后一个波浪线,然后截断字符串,再找倒数第二个波浪线。如果有第二个,就取两者之间的内容,否则取最后一个后的内容。现在需要根据波浪线数量调整策略。
首先,我需要分析每个字符串中的波浪线数量。比如,字符串里可能有多个波浪线,比如三个。原来的代码使用strrchr来找最后一个波浪线,然后截断,再找倒数第二个。但这样处理可能无法正确识别中间的波浪线位置,尤其是在有多个的情况下。
首先,我需要遍历每个字符串,统计波浪线的总数。可以用strchr循环查找,记录所有波浪线的位置。例如,遍历整个字符串,记录每个波浪线的指针位置到一个数组中。然后根据这个数组的长度(波浪线数量)来决定如何处理。
比如,假设有一个字符串是"a~b~c~d",波浪线数量是3个。根据需求,当有3个波浪线时,应该取第二个和第三个之间的内容,也就是"c"。而原来的代码处理方式可能无法正确获取这个部分,因为它总是找最后两个波浪线。
因此,我需要重新设计逻辑,步骤如下:
1. 对于每个字符串,先统计所有波浪线的位置,保存到一个指针数组里。
2. 根据波浪线的数量,决定取哪部分:
- 数量为1:取最后一个波浪线后的内容。
- 数量为2:取第一个和第二个之间的内容。
- 数量>=3:取第二个和第三个之间的内容。
3. 处理截取后的字符串,去除前后空白。
4. 将处理后的字符串替换原数组中的元素。
现在,我需要修改代码中的循环部分。原来的代码在处理时,先找到最后一个波浪线,然后将字符串截断到最后一个波浪线前,再找倒数第二个。这可能无法正确获取第二个和第三个波浪线的位置,尤其是在总数量超过3的情况下。
例如,假设字符串是"~one~two~three",有3个波浪线。按用户需求,应该取第二个和第三个之间的内容,即"two"。但是原来的代码在找到最后一个波浪线后,截断字符串到最后一个波浪线之前,也就是"~one~two",然后再找倒数第二个波浪线,即位置0的波浪线,这样得到的是"one"到"two"之间的部分,而实际上用户希望的是第二个和第三个之间的,即第三个波浪线可能存在的位置可能没有被正确捕获。
因此,正确的做法应该是收集所有波浪线的位置,然后根据数量选择对应的区间。这样无论总共有多少个波浪线,都能准确找到所需的区间。
接下来,修改代码的具体步骤:
在循环处理每个字符串时:
- 将字符串复制到tempStr。
- 使用strtok或者循环遍历的方式,找到所有波浪线的位置,并保存到一个数组里。例如,使用一个指针数组char* delims[MAX_DELIMS],其中MAX_DELIMS足够大,比如256。
- 统计波浪线的数量,即count = delims数组的长度。
- 根据count的值来决定如何选择起始和结束位置:
- count ==1:目标字符串是最后一个波浪线后的内容。
- count ==2:目标字符串是第一个和第二个波浪线之间的内容。
- count >=3:目标字符串是第二个和第三个波浪线之间的内容。
- 然后处理目标字符串,去除前后空白,并替换原数组中的元素。
需要注意的是,原来的代码中,在查找波浪线时,可能没有处理所有可能的波浪线位置,而是只处理了最后两个。现在需要全部遍历,记录所有位置。
但是,在C语言中,如何收集所有波浪线的位置呢?可以用循环,每次用strchr从当前位置开始查找下一个波浪线,直到找不到为止。
例如,初始化一个指针数组delims,然后循环查找:
char* current = tempStr;
int count = 0;
while ((current = strchr(current, cDelim)) != NULL) {
delims[count++] = current;
current++; // 移动到下一个字符继续查找
}
这样,delims数组中就保存了所有波浪线的位置指针,count是波浪线的总数。
然后根据count的值:
- 如果count ==0,跳过。
- count ==1:取最后一个(即delims[0])后的内容。
- count ==2:取delims[0]到delims[1]之间的内容。
- count >=3:取delims[1]到delims[2]之间的内容。
但这里有一个问题,比如当count >=3时,第二个和第三个波浪线之间的内容。例如,字符串是a~b~c~d,三个波浪线,那么delims[0]指向第一个~,delims[1]指向第二个~,delims[2]指向第三个~。此时,第二个和第三个之间的内容是c。因此,起始位置是delims[1] +1,结束位置是delims[2]。而delims[2]是第三个波浪线的指针,所以目标字符串是从delims[1]+1到delims[2]-1的位置,然后用'\0'截断。
或者,将两个指针之间的部分提取出来。例如,在delims[1]+1到delims[2]-1之间的内容,然后复制到目标字符串中。
需要注意的是,原代码的处理方式是将tempStr截断,通过插入'\0'来修改字符串。可能需要调整这种方法。
举个例子,假设tempStr是"abc~def~ghi~jkl",波浪线数量是3。delims数组中的三个指针分别指向第一个、第二个、第三个~。现在需要取第二个和第三个之间的内容,即"ghi"。那么,我们需要将第三个波浪线的位置设为结束符,然后将起始位置设为第二个波浪线+1,结束位置为第三个波浪线的位置-1。
可能的步骤:
当count >=3时:
start = delims[1] +1;
end = delims[2] -1;
但是,这里需要确保start不超过end。或者,直接截取从delims[1]+1到delims[2]之间的内容,即把第三个波浪线替换为'\0',然后目标字符串是delims[1]+1到该位置。
例如:
*delims[2] = '\0';
target = delims[1] +1;
这样,目标字符串就是从第二个波浪线后到第三个波浪线前的内容。
同样地,当count ==2时,需要将第二个波浪线替换为'\0',然后目标字符串是第一个波浪线后的内容,到第二个波浪线前。
当count ==1时,直接取最后一个波浪线后的内容,不需要截断后面的部分。
但是原来的代码在找到lastDelim后,将*lastDelim设置为'\0',然后找倒数第二个波浪线。现在需要完全不同的处理方式。
现在,我需要重新实现这部分逻辑。
具体步骤:
在循环处理每个字符串时:
1. 复制字符串到tempStr。
2. 查找所有波浪线的位置,保存在delims数组中,并统计数量count。
3. 如果count ==0,跳过。
4. 否则:
a. 如果count ==1:
- target是最后一个波浪线后的内容,即delims[0]+1。
b. 如果count ==2:
- 将第二个波浪线位置设为'\0',target是delims[0]+1到delims[1]之间的内容。
c. 如果count >=3:
- 将第三个波浪线位置设为'\0',target是delims[1]+1到delims[2]之间的内容。
然后,处理target的前后空白,并赋值回数组。
但这里存在一个问题,当处理多个波浪线时,如何修改tempStr来截断字符串?
例如,对于count >=3的情况,我们需要将第三个波浪线的位置设为'\0',这样target就是从delims[1]+1到该位置的内容。例如:
原字符串是"a~b~c~d",波浪线在位置1、3、5。delims数组中的三个指针分别指向位置1、3、5。当把第三个波浪线设为'\0'时,字符串变为"a~b~c\0d",那么delims[1]+1指向位置4(即字符c),而整个字符串到位置5的'\0'结束,所以target是"c"。
这似乎正确。
同样,当count ==2时,把第二个波浪线设为'\0',则delims[0]+1到delims[1]之间的内容就是第一个和第二个波浪线之间的部分。
例如,字符串"a~b~c",波浪线在位置1和3。将第二个波浪线设为'\0',字符串变成"a~b\0c",则target是delims[0]+1(即位置2,字符b),到'\0'前,即得到"b"。
而当count ==1时,target就是最后一个波浪线后的部分,不需要截断。
这样,正确的步骤是:
根据count的值:
- count >=3:
- 将第三个波浪线替换为'\0',target是第二个波浪线后的内容。
- count ==2:
- 将第二个波浪线替换为'\0',target是第一个波浪线后的内容。
- count ==1:
- target是第一个波浪线后的内容。
但原需求是:
- 1个波浪线:取最后一个后的内容(即唯一的一个)。
- 2个波浪线:取第一个和第二个之间的。
- 3个及以上:取第二个和第三个之间的。
所以,在count >=3时,目标区间是第二个和第三个波浪线之间的内容。也就是说,需要截取从第二个波浪线后的字符到第三个波浪线前的内容。因此,需要将第三个波浪线的位置设为'\0',然后target是第二个波浪线后的位置。
所以,修改代码的逻辑:
当count >=3时:
将第三个波浪线的位置替换为'\0',这样字符串结束于第三个波浪线的位置,而target从第二个波浪线+1开始。
当count ==2时:
将第二个波浪线替换为'\0',target从第一个波浪线+1开始。
当count ==1时:
target从第一个波浪线+1开始,不需要截断后面。
然后,处理target的前后空白。
这样,我需要调整原来的代码逻辑,以收集所有波浪线的位置,并根据数量处理。
现在,如何在代码中实现这个?
首先,收集所有波浪线到delims数组:
char tempStr[nBufSize];
sprintf_s(tempStr, ...);
char* delims[256]; // 假设最多有256个波浪线,防止溢出
int count = 0;
char* current = tempStr;
while ((current = strchr(current, cDelim)) != NULL) {
delims[count++] = current;
current++; // 继续查找下一个
}
然后,根据count处理:
if (count == 0) continue;
if (count == 1) {
target = delims[0] + 1;
} else if (count == 2) {
// 将第二个波浪线替换为'\0'
*delims[1] = '\0';
target = delims[0] + 1;
} else { // count >=3
// 将第三个波浪线替换为'\0'
*delims[2] = '\0';
target = delims[1] + 1;
}
但这样处理可能有问题。例如,当count >=3时,第三个波浪线可能后面还有更多波浪线,但因为我们替换了第三个波浪线为'\0',后面的波浪线可能不会被处理,但根据需求,只需要第二和第三个之间的内容,所以后面的可以忽略。
这样处理之后,target就是正确的区间。例如,当count >=3时,第三个波浪线被替换为'\0',所以字符串结束于第三个波浪线的位置,而target从第二个波浪线后开始,直到第三个波浪线前。
接下来,处理target的前后空格和制表符:
原来的代码已经处理了这个部分,可以保留:
while(*target == ' ' || *target == '\t') target++;
char* end = target + strlen(target) - 1;
while(end >= target && (*end == ' ' || *end == '\t')) end--;
*(end + 1) = '\0';
然后将结果写回nxStrsList。
需要注意的是,当count >=3时,如果第三个波浪线后面的内容可能被忽略,因为已经将第三个波浪线替换为'\0'。例如,字符串是"~a~b~c",处理后第三个波浪线变为'\0',所以字符串变为"~a~b\0c",此时target是第二个波浪线后的"b",因为第三个波浪线被截断,所以正确。
现在,需要测试几个例子:
测试用例1:一个波浪线,字符串为"test~after",处理后应该取"after"。
测试用例2:两个波浪线,"part1~part2~part3",count是2?或者原字符串可能为"a~b~c",此时count是2?假设字符串是"a~b~c",波浪线在位置1和3,count是2。处理时,第二个波浪线被替换为'\0',字符串变成"a~b\0c",target是delims[0]+1,即"b"。
测试用例3:三个波浪线,"~one~two~three",count是3。第三个波浪线被替换为'\0',所以字符串变为"~one~two\0three",target是第二个波浪线后的"two"。
这正是用户想要的。
现在,我需要修改代码中的相关部分,将原来的查找最后一个波浪线改为收集所有波浪线,并根据数量处理。
但原来的代码可能使用了strrchr函数,现在需要更改为遍历所有波浪线。
此外,需要注意数组越界问题,比如当有超过256个波浪线时,但实际中可能不会出现,或者可以动态分配,但这里为了简单,暂时用固定大小的数组。
现在,将原来的代码修改为:
void StdCategory::extractBetweenTildes(vector<NXString>* nxStrsList)
{
const char cDelim = '~';
const int nBufSize = 200;
char tempStr[nBufSize];
for(size_t i = 0; i < nxStrsList->size(); i++)
{
sprintf_s(tempStr, nBufSize, "%s", (*nxStrsList)[i].getLocaleText());
// 收集所有波浪线位置
char* delims[256];
int count = 0;
char* current = tempStr;
while (count < 256 && (current = strchr(current, cDelim)) != nullptr) {
delims[count++] = current;
current++; // 移动到下一个字符继续查找
}
if (count == 0) {
continue; // 无波浪线,跳过
}
char* target = nullptr;
if (count == 1) {
// 一个波浪线,取后面的内容
target = delims[0] + 1;
} else if (count == 2) {
// 两个波浪线,取第一个和第二个之间的内容
*delims[1] = '\0'; // 截断到第二个波浪线
target = delims[0] + 1;
} else {
// 三个或更多,取第二个和第三个之间的内容
*delims[2] = '\0'; // 截断到第三个波浪线
target = delims[1] + 1;
}
// 处理前后空白
if (target != nullptr) {
while (*target == ' ' || *target == '\t') {
target++;
}
char* end = target + strlen(target) - 1;
while (end >= target && (*end == ' ' || *end == '\t')) {
end--;
}
*(end + 1) = '\0';
// 回写结果
(*nxStrsList)[i] = target;
}
}
}
这样修改后,应该满足用户的需求。但需要注意以下几点:
1. 当count >=3时,第三个波浪线可能不存在?例如,如果count是3,delims[2]一定存在,因为已经收集了三个指针。所以,替换为'\0'是安全的。
2. 当target为空的情况,比如两个连续的波浪线,例如"a~~b",count为2时,delims[0]是第一个~,delims[1]是第二个~。替换第二个~为'\0'后,target是第一个~后的内容,即空字符串。处理后,target会被去前后空白,变成空字符串。这可能符合预期,还是需要根据需求决定是否允许空字符串。
此外,需要测试当波浪线位于字符串开头或末尾的情况。例如:
案例4:字符串是"~test",一个波浪线,取后的内容"test"。
案例5:字符串是"test~",count为1,target是波浪线后的空字符串,处理后变成空字符串。
案例6:字符串是"~a~b~",count为3,第三个波浪线是最后一个字符。替换为'\0'后,target是第二个波浪线后的内容"b"。
案例7:字符串是"~a~b~c~d",count为4。处理时,第三个波浪线被替换为'\0',target是第二个波浪线后的"b",而c和d被截断。
这些情况都应正确处理。
另外,需要注意tempStr的大小是200,如果原字符串超过这个长度,可能会导致截断或溢出。但原代码使用了sprintf_s,第三个参数是缓冲区大小,所以应该安全,但可能丢失数据。不过这可能属于原函数的问题,不在当前修改范围内。
综上,上述修改后的代码应该满足用户的需求。</think>以下是修改后的函数实现及分步说明:
```cpp
/******************************************************************************
函数名称:extractBetweenTildes
功能说明:根据波浪线数量提取内容:
1个~取最后一个~后的字符串,2个~取1-2间内容,3+个~取2-3间内容
返 回 值:void
参 数:vector<NXString>* nxStrsList
作 者: LuoPengyu
修改日期: 2025/3/18(更新逻辑)
******************************************************************************/
void StdCategory::extractBetweenTildes(vector<NXString>* nxStrsList)
{
const char cDelim = '~';
const int nBufSize = 200;
char tempStr[nBufSize];
for(size_t i = 0; i < nxStrsList->size(); i++)
{
sprintf_s(tempStr, nBufSize, "%s", (*nxStrsList)[i].getLocaleText());
// 收集所有波浪线位置
char* delims[256]; // 存储最多256个波浪线位置
int count = 0;
char* current = tempStr;
while (count < 256 && (current = strchr(current, cDelim)) != nullptr) {
delims[count++] = current;
current++; // 移动到下一个字符继续查找
}
if (count == 0) {
continue; // 无波浪线则跳过
}
char* target = nullptr;
// 根据波浪线数量选择截取策略
if (count == 1) {
// 情况1:1个波浪线,取最后(唯一)一个后的内容
target = delims[0] + 1;
} else if (count == 2) {
// 情况2:2个波浪线,截断到第二个波浪线,取中间内容
*delims[1] = '\0';
target = delims[0] + 1;
} else {
// 情况3:3+个波浪线,截断到第三个波浪线,取第二三个间内容
*delims[2] = '\0';
target = delims[1] + 1;
}
// 去除前后空白
while(*target == ' ' || *target == '\t') target++;
char* end = target + strlen(target) - 1;
while(end >= target && (*end == ' ' || *end == '\t')) end--;
*(end + 1) = '\0';
// 回写处理结果
(*nxStrsList)[i] = target;
}
}
```
### 分步说明:
1. **数据收集阶段**
- 将字符串复制到临时缓冲区`tempStr`中。
- 使用`strchr`遍历字符串,记录所有波浪线`~`的位置到数组`delims`中,并统计总数`count`。
2. **逻辑判断阶段**
- **无波浪线**:跳过当前字符串。
- **1个波浪线**:直接取波浪线后的内容(`delims[0] + 1`)。
- **2个波浪线**:将第二个波浪线替换为结束符`\0`,取第一个波浪线到第二个波浪线之间的内容。
- **3个或更多波浪线**:将第三个波浪线替换为结束符`\0`,取第二个到第三个波浪线之间的内容。
3. **字符串清理阶段**
- 去除目标字符串的前后空白字符(空格和制表符)。
- 将处理后的结果写回原数组。
### 关键修改点说明:
- **逻辑分层**:通过统计波浪线数量明确区分三种情况,避免原代码中仅关注最后两个波浪线的局限性。
- **精准截断**:通过修改特定位置的波浪线为结束符`\0`,直接利用字符串指针操作提取目标区间。
- **鲁棒性增强**:增加对波浪线数量的全面判断,确保不同数量下的逻辑正确性。
阅读全文