使用strtok从字符串中解析空标记

我的应用程序生成如下所示的字符串。 我需要将分隔符之间的值解析为单个值。

2342|2sd45|dswer|2342||5523|||3654|Pswt 

我正在使用strtok在循环中执行此操作。 对于第五个标记,我得到5523.但是,我需要考虑两个分隔符之间的空值|| 同样。 根据我的要求,5523应该是第六个标记。

 token = (char *)strtok(strAccInfo, "|"); for (iLoop=1;iLoop<=106;iLoop++) { token = (char *)strtok(NULL, "|"); } 

有什么建议?

在这种情况下,我经常更喜欢p2 = strchr(p1, '|')memcpy(s, p1, p2-p1)p2 = strchr(p1, '|')循环。 它很快,不会破坏输入缓冲区(因此它可以与const char *一起使用)并且非常便携(即使在嵌入式上)。

它也是可重入的; strtok不是。 (BTW:reentrant与multithreading无关strtok_r已经使用嵌套循环中断了。可以使用strtok_r但它不是那么便携。)

在第一次调用时,函数需要一个C字符串作为str的参数,其第一个字符用作扫描标记的起始位置。 在后续调用中,函数需要一个空指针,并在最后一个标记结束后立即使用该位置作为扫描的新起始位置。

为了确定令牌的开始和结束,该函数首先从起始位置扫描未包含在分隔符中的第一个字符(它成为令牌的开头)。 然后从令牌的这个开头开始扫描包含在分隔符中的第一个字符,这将成为令牌的结尾。

这说的是它会跳过任何’|’ 令牌开头的字符。 使5523成为您已经知道的第五个令牌。 只是想我会解释原因(我必须自己查阅)。 这也表示你不会获得任何空标记。

由于您的数据是以这种方式设置的,因此您有几种可能的解决方案:
1)找到所有出现的|| 并用|替换 | (在那里放一个空格)
2)做5次strstr并找到第5个元素的开头。

 char *mystrtok(char **m,char *s,char c) { char *p=s?s:*m; if( !*p ) return 0; *m=strchr(p,c); if( *m ) *(*m)++=0; else *m=p+strlen(p); return p; } 
  • 折返
  • 线程
  • 严格符合ANSI标准
  • 需要一个未使用的帮助指针来自调用上下文

例如

 char *p,*t,s[]="2342|2sd45|dswer|2342||5523

3654|Pswt”; for(t=mystrtok(&p,s,’|’);t;t=mystrtok(&p,0,’|’)) puts(t);

例如

 char *p,*t,s[]="2,3,4,2|2s,d4,5|dswer|23,42||5523

3654|Pswt”; for(t=mystrtok(&p,s,’|’);t;t=mystrtok(&p,0,’|’)) { char *p1,*t1; for(t1=mystrtok(&p1,t,’,’);t1;t1=mystrtok(&p1,0,’,’)) puts(t1); }

你的工作:)实现char * c作为参数3

请考虑使用strsep: strsep reference

这是strtok的限制。 设计师考虑到了以空格分隔的令牌。 无论如何, strtok并没有做太多事情; 只需滚动自己的解析器。 C FAQ有一个例子 。

使用strtok以外的东西。 它根本不打算做你想要的。 当我需要这个时,我通常使用strcspnstrpbrk并自己处理其余的令牌。 如果你不介意像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; } 

以下是现在适合我的解决方案。 感谢所有回复的人。

我正在使用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; } } }