如何安全解析制表符分隔的字符串?

如何安全解析制表符分隔符字符串? 例如:test \ tbla-bla-bla \ t2332?

strtok()是一个标准函数,用于解析具有任意分隔符的字符串。 但是,它不是线程安全的。 您选择的C库可能具有线程安全的变体。

另一种符合标准的方式(只是写了这个,它没有经过测试 ):

 #include  #include  int main() { char string[] = "foo\tbar\tbaz"; char * start = string; char * end; while ( ( end = strchr( start, '\t' ) ) != NULL ) { // %s prints a number of characters, * takes number from stack // (your token is not zero-terminated!) printf( "%.*s\n", end - start, start ); start = end + 1; } // start points to last token, zero-terminated printf( "%s", start ); return 0; } 

使用strtok_r而不是strtok(如果可用)。 它有类似的用法,除了它是可重入的,它不会像strtok那样修改字符串。 [ 编辑:实际上,我错过了。 正如Christoph指出的那样,strtok_r确实用’\ 0’代替了分隔符。 因此,如果要保留原始字符串,则应对字符串的副本进行操作。 但它最好是strtok因为它是可重入且线程安全的]

strtok将保留原始字符串修改。 它用’\ 0’替换分隔符。 如果你的字符串碰巧是一个常量,存储在只读内存中(某些编译器会这样做),你实际上可能会遇到访问冲突。

使用string.h strtok()

 #include  #include  int main () { char str[] = "test\tbla-bla-bla\t2332"; char * pch; pch = strtok (str," \t"); while (pch != NULL) { printf ("%s\n",pch); pch = strtok (NULL, " \t"); } return 0; } 

您可以使用任何正则表达式库甚至GLib GScanner ,有关详细信息,请参阅此处和此处 。

又一个版本; 这个将逻辑分成一个新函数

 #include  static _Bool next_token(const char **start, const char **end) { if(!*end) *end = *start; // first call else if(!**end) // check for terminating zero return 0; else *start = ++*end; // skip tab // advance to terminating zero or next tab while(**end && **end != '\t') ++*end; return 1; } int main(void) { const char *string = "foo\tbar\tbaz"; const char *start = string; const char *end = NULL; // NULL value indicates first call while(next_token(&start, &end)) { // print substring [start,end[ printf("%.*s\n", end - start, start); } return 0; } 

如果您需要二进制安全方式来标记给定字符串:

 #include  #include  void tokenize(const char *str, const char delim, const size_t size) { const char *start = str, *next; const char *end = str + size; while (start < end) { if ((next = memchr(start, delim, end - start)) == NULL) { next = end; } printf("%.*s\n", next - start, start); start = next + 1; } } int main(void) { char str[] = "test\tbla-bla-bla\t2332"; int len = strlen(str); tokenize(str, '\t', len); return 0; }