【问题标题】:splitting string and counting tokens in c在c中拆分字符串和计数标记
【发布时间】:2021-12-08 01:55:26
【问题描述】:

我有一个文本文件,其中包含多个不同长度的字符串,我需要将这些字符串拆分为标记。 是否最好使用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 是这条路。如果您不确定它是如何工作的,请阅读Documentation。如果需要线程安全,请确保使用strtok_rstrtok 在找不到更多令牌时返回 NULL。这就是你可以计算代币数量的方法。
  • @vsr: strtok() 很少是适合任何事情的工具。在这种情况下,尚不清楚## 的序列是否等同于单个#,以及出现在行首或行尾的# 是否应被忽略...strtok() 做出了强有力的假设:这些情况可能不是预期的行为。

标签: c string split


【解决方案1】:

strtok() 很少是适合任何事情的工具。在这种情况下,不清楚##的序列是否等同于单个#,以及出现在行首或行尾的#是否应该被忽略......

strtok() 对这些可能不是预期行为的情况做出了强有力的假设。

此外,strtok() 修改了它的字符串参数并使用了隐藏的静态状态,这使得它在多线程程序中不安全,并且在嵌套用例中容易出现编程错误。 strtok_r() 可以解决这些问题,但语义仍然有些违反直觉。

为了您的目的,您必须准确定义什么是标记和分隔符。如果允许空token,strtok()绝对不是解决办法。

【讨论】:

    【解决方案2】:

    一般来说,使用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 的另一个缺点是它不是reentrantthread-safe,而strchr 是。不过有些平台提供了strtok_r的功能,没有这些缺点。但是这个功能确实还是有破坏性的缺点。

    【讨论】:

      【解决方案3】:

      您也可以编写自己的函数来处理这个非常简单的拆分:

      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 将被修改。

      【讨论】:

        【解决方案4】:

        是的,您应该使用strtok 来拆分这些字符串。

        开启

        我如何计算令牌

        您可以简单地在while 中添加一个计数器,并在每次迭代中将其加一以获得令牌总数。

        #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;
        }
        

        【讨论】:

          猜你喜欢
          • 2021-03-30
          • 1970-01-01
          • 1970-01-01
          • 2011-01-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-09-15
          相关资源
          最近更新 更多