C:使用strtok解析字符串中的空标记
我的应用程序生成如下所示的字符串。我需要将分隔符之间的值解析为单个值C:使用strtok解析字符串中的空标记,c,string,C,String,我的应用程序生成如下所示的字符串。我需要将分隔符之间的值解析为单个值 2342|2sd45|dswer|2342||5523|||3654|Pswt 我正在使用strtok在循环中执行此操作。第五个标记是5523。但是,我还需要考虑两个分隔符之间的空值。根据我的要求,5523应该是第六个代币 token = (char *)strtok(strAccInfo, "|"); for (iLoop=1;iLoop<=106;iLoop++) { token = (
2342|2sd45|dswer|2342||5523|||3654|Pswt
我正在使用strtok
在循环中执行此操作。第五个标记是5523。但是,我还需要考虑两个分隔符之间的空值。根据我的要求,5523应该是第六个代币
token = (char *)strtok(strAccInfo, "|");
for (iLoop=1;iLoop<=106;iLoop++) {
token = (char *)strtok(NULL, "|");
}
token=(char*)strtok(strAccInfo,“|”);
对于(iLoop=1;iLoop
在第一次调用时,函数期望
一个C字符串作为str的参数,其
第一个字符用作
开始扫描令牌的位置。
在随后的调用中,函数
需要空指针并使用
位置正好在最后一个结束后
令牌作为的新起始位置
扫描
决定开始和结束
对于令牌,函数首先扫描
从
中未包含的第一个字符
分隔符(成为
标记的开始),然后
从本节开始扫描
第一个字符的标记
包含在分隔符中,将成为
令牌的结尾
这意味着它将跳过令牌开头的任何“|”字符。将5523作为第五个令牌,这是您已经知道的。我只是想解释一下原因(我必须自己查找)。这还表示您不会得到任何空令牌
由于您的数据是以这种方式设置的,因此您有两种可能的解决方案:
1) 查找所有出现的| |并替换为| |(在其中添加空格)
2) 做一个strstr 5次,然后找到第5个元素的开头。用strep代替:这是strok的一个限制。设计者考虑到了用空格分隔的标记<代码>strtok
反正也没什么作用;只需滚动您自己的解析器。.使用的不是strtok
。它根本不是为了满足你的要求。当我需要时,我通常使用strcspn
或strpbrk
自己处理其余的令牌。如果您不介意修改输入字符串,比如strtok
,它应该非常简单。至少现在,类似这样的事情似乎应该奏效:
// Warning: untested code. Should really use something with a less-ugly interface.
char *tokenize(char *input, char const *delim) {
static char *current; // just as ugly as strtok!
char *pos, *ret;
if (input != NULL)
current = input;
if (current == NULL)
return current;
ret = current;
pos = strpbrk(current, delim);
if (pos == NULL)
current = NULL;
else {
*pos = '\0';
current = pos+1;
}
return ret;
}
在这种情况下,我通常更喜欢
p2=strchr(p1,“|”)
循环,内部有memcpy(s,p1,p2-p1)
。它速度快,不会破坏输入缓冲区(因此可以与const char*
)一起使用),而且非常可移植(即使在嵌入式系统上)
它也是可重入的<代码>strtok不是。(顺便说一句:可重入与多线程无关。
strtok
已经用嵌套循环中断了。可以使用strtok\u r
,但它不是便携的。)下面是我现在正在使用的解决方案。感谢你们所有的回应
我正在使用LoadRunner。因此,有一些不熟悉的命令,但我相信流程很容易理解
char strAccInfo[1024], *p2;
int iLoop;
Action() { //This value would come from the wrsp call in the actual script.
lr_save_string("323|90||95|95|null|80|50|105|100|45","test_Param");
//Store the parameter into a string - saves memory.
strcpy(strAccInfo,lr_eval_string("{test_Param}"));
//Get the first instance of the separator "|" in the string
p2 = (char *) strchr(strAccInfo,'|');
//Start a loop - Set the max loop value to more than max expected.
for (iLoop = 1;iLoop<200;iLoop++) {
//Save parameter names in sequence.
lr_param_sprintf("Param_Name","Parameter_%d",iLoop);
//Get the first instance of the separator "|" in the string (within the loop).
p2 = (char *) strchr(strAccInfo,'|');
//Save the value for the parameters in sequence.
lr_save_var(strAccInfo,p2 - strAccInfo,0,lr_eval_string("{Param_Name}"));
//Save string after the first instance of p2, as strAccInfo - for looping.
strcpy(strAccInfo,p2+1);
//Start conditional loop for checking for last value in the string.
if (strchr(strAccInfo,'|')==NULL) {
lr_param_sprintf("Param_Name","Parameter_%d",iLoop+1);
lr_save_string(strAccInfo,lr_eval_string("{Param_Name}"));
iLoop = 200;
}
}
}
charstraccinfo[1024],*p2;
int iLoop;
Action(){//此值将来自实际脚本中的wrsp调用。
lr|U保存|U字符串(“323 | 90 | 95 | 95 | null | 80 | 50 | 105 | 100 | 45”,“测试参数”);
//将参数存储到字符串中-节省内存。
strcpy(strAccInfo,lr_eval_字符串(“{test_Param}”);
//获取字符串中分隔符“|”的第一个实例
p2=(char*)strchr(strAccInfo,“|”);
//启动循环-将“最大循环”值设置为超出预期的最大值。
对于(iLoop=1;iLoop
- 凹入的
- 线程安全
- 严格符合ANSI标准
- 需要调用未使用的帮助指针
上下文
e、 g
e、 g
你的作品:)
将char*c实现为参数3受我创建此函数的启发,它应该是线程安全的,支持空令牌,并且不会更改原始字符串
char* strTok(char** newString, char* delimiter)
{
char* string = *newString;
char* delimiterFound = (char*) 0;
int tokLenght = 0;
char* tok = (char*) 0;
if(!string) return (char*) 0;
delimiterFound = strstr(string, delimiter);
if(delimiterFound){
tokLenght = delimiterFound-string;
}else{
tokLenght = strlen(string);
}
tok = malloc(tokLenght + 1);
memcpy(tok, string, tokLenght);
tok[tokLenght] = '\0';
*newString = delimiterFound ? delimiterFound + strlen(delimiter) : (char*)0;
return tok;
}
你可以像这样使用它
char* input = "1,2,3,,5,";
char** inputP = &input;
char* tok;
while( (tok=strTok(inputP, ",")) ){
printf("%s\n", tok);
}
这是一个假设输出
1
2
3
5
我测试了它的简单字符串,但还没有在生产中使用它,并且也发布了它,所以你可以看到其他人对它的看法strtok()可以说是C标准中最糟糕的东西。你可以编写自己的解析器。因为OP只搜索一个分隔符,strcher()
可以用来代替strpbrk()
。我做的有点不同。无论如何,谢谢。谢谢你提供的信息。希望我下次需要时能记住这一点。:-D你的第一个解决方案会把我的结果搞砸,因为字符串中有一些有效的组件会在管道之间返回一个空格。第二个解决方案可能会变得单调乏味,可能无法实现因为不同数据集的字符串可能不同。@Bash-很抱歉,我无法提供更多帮助:(哦,你帮了很多忙……信息就是我们领域的力量,对吗?我从你发布的链接中获得了一些有用的信息。谢谢!我使用了你的输入并更新了我的代码。谢谢!如果你感兴趣,我有下面的代码作为答案。谢谢,受你回答的启发,我很抱歉Patrick,但你能详细解释一下怎么做吗你的解决方案有效吗?我猜s
是原始字符串,但是p1
和p2
是什么?在某个时候,你需要解释为什么你有全局变量而不是局部变量,为什么你没有函数的返回类型(这是非常古老的C风格)。或者,更好的方法是修复代码,使其在严格的编译器警告下干净地编译。使用iLoop=200;
来实现break;
是脆弱的。不清楚循环控制中为什么要使用200。哦,好吧:-)我的大部分代码都在UNIX上,现在肯定会派上用场:-))以前从未听说过。如果你在Posix机器上,你可以替换'tok=malloc(tokLenght+1);memcpy(tok,string,tokLenght);tok[tokLenght]='\0';''只需tok=strndup(string,tokLength);
char* strTok(char** newString, char* delimiter)
{
char* string = *newString;
char* delimiterFound = (char*) 0;
int tokLenght = 0;
char* tok = (char*) 0;
if(!string) return (char*) 0;
delimiterFound = strstr(string, delimiter);
if(delimiterFound){
tokLenght = delimiterFound-string;
}else{
tokLenght = strlen(string);
}
tok = malloc(tokLenght + 1);
memcpy(tok, string, tokLenght);
tok[tokLenght] = '\0';
*newString = delimiterFound ? delimiterFound + strlen(delimiter) : (char*)0;
return tok;
}
char* input = "1,2,3,,5,";
char** inputP = &input;
char* tok;
while( (tok=strTok(inputP, ",")) ){
printf("%s\n", tok);
}
1
2
3
5