繁体   English   中英

在 c 中拆分字符串和计数标记

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM