[英]splitting string and counting tokens in c
我有一个文本文件,其中包含多个不同长度的字符串,我需要将这些字符串拆分为标记。 最好使用strtok
来拆分这些字符串以及如何计算令牌?
文件中的字符串示例
Emma Stone#1169876#COMP242#COMP333#COMP336#COMP133#COMP231
Emma Watson#1169875#COMP336#COMP2421#COMP231#COMP338#CCOMP3351
Kevin Hart#1146542#COMP142#COMP242#COMP231#COMP336#COMP331#COMP334
George Clooney#1164561#COMP336#COMP2421#COMP231#COMP338#CCOMP3351
Matt Damon#1118764#COMP439#COMP4232#COMP422#COMP311#COMP338
Johnny Depp#1019876#COMP311#COMP242#COMP233#COMP3431#COMP333#COMP432
一般来说,使用strtok
是一个很好的解决问题的方法:
#include <stdio.h>
#include <string.h>
int main( void )
{
char line[] =
"Emma Stone#1169876#COMP242#COMP333#COMP336#COMP133#COMP231";
char *p;
int num_tokens = 0;
p = strtok( line, "#" );
while ( p != NULL )
{
num_tokens++;
printf( "Token #%d: %s\n", num_tokens, p );
p = strtok( NULL, "#" );
}
}
该程序具有以下输出:
Token #1: Emma Stone
Token #2: 1169876
Token #3: COMP242
Token #4: COMP333
Token #5: COMP336
Token #6: COMP133
Token #7: COMP231
但是,使用strtok
一个缺点是它具有破坏性,因为它通过用终止空字符替换#
分隔符来修改字符串。 如果你不想要这个,那么你可以使用strchr
代替:
#include <stdio.h>
#include <string.h>
int main( void )
{
const char *const line =
"Emma Stone#1169876#COMP242#COMP333#COMP336#COMP133#COMP231";
const char *p = line, *q;
int num_tokens = 1;
while ( ( q = strchr( p, '#' ) ) != NULL )
{
printf( "Token #%d: %.*s\n", num_tokens, q-p, p );
num_tokens++;
p = q + 1;
}
printf( "Token #%d: %s\n", num_tokens, p );
}
这个程序与第一个程序有相同的输出:
Token #1: Emma Stone
Token #2: 1169876
Token #3: COMP242
Token #4: COMP333
Token #5: COMP336
Token #6: COMP133
Token #7: COMP231
strtok
另一个缺点是它不是可重入或线程安全的,而strchr
是。 然而,一些平台提供了一个函数strtok_r
,它没有这些缺点。 但该功能仍然具有破坏性的缺点。
是的,您应该使用strtok
来拆分这些字符串。
在
我如何计算令牌
您可以简单地在while
内添加一个计数器while
并在每次迭代中将其递增 1 以获得令牌总数。
#include <stdio.h>
#include <string.h>
int main(void) {
char string[] = "Hello world this is a simple string";
char *token = strtok(string, " ");
int count = 0;
while (token != NULL) {
count++;
token = strtok(NULL, " ");
}
printf("Total number of tokens = %d", count);
return 0;
}
您还可以编写自己的函数来处理这个非常琐碎的拆分:
char **split(char *str, char **argv, size_t *argc, const char delim)
{
*argc = 0;
if(*str && *str)
{
argv[0] = str;
*argc = 1;
while(*str)
{
if(*str == delim)
{
*str = 0;
str++;
if(*str)
{
argv[*argc] = str;
*argc += 1;
continue;
}
}
str++;
}
}
return argv;
}
int main(void)
{
char *argv[10];
size_t argc;
char str[] = "Emma Stone#1169876#COMP242#COMP333#COMP336#COMP133#COMP231";
split(str, argv, &argc, '#');
printf("Numner of substrings: %zu\n", argc);
for(size_t i = 0; i < argc; i++)
printf("token [%2zu] = `%s`\n", i, argv[i]);
}
https://godbolt.org/z/b1aarnfWs
备注:与 strtok 相同,它需要str
对我来说是可修改的。 str
将被修改。
strtok()
很少是适合任何事情的工具。 在这种情况下,目前还不清楚的序列是否##
相当于一个#
以及是否#
出现在开头或线的一端可忽略不计...
strtok()
对这些可能不是预期行为的情况做出了强有力的假设。
此外, strtok()
修改其字符串参数并使用隐藏的静态状态,这使其在多线程程序中不安全,并且在嵌套用例中容易出现编程错误。 strtok_r()
在可用的情况下解决了这些问题,但语义仍然有些违反直觉。
为了您的目的,您必须精确定义什么是标记和分隔符。 如果允许空标记, strtok()
绝对不是解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.