【问题标题】:how to tokenize string to array of int in c?如何在c中将字符串标记为int数组?
【发布时间】:2010-12-01 18:39:18
【问题描述】:

有人知道从文本文件中每行读取一个序列号并将其解析为 C 中的数组吗?

我在文件中的内容:

12 3 45 6 7 8
3 5 6 7
7 0 -1 4 5

我想要的程序:

array1[] = {12, 3, 45, 6, 7, 8};
array2[] = {3, 5, 6, 7};
array3[] = {7, 0, -1, 4, 5};

我已经通过几种方式来阅读它,但唯一的问题是只有当我想每行标记它时。 谢谢。

【问题讨论】:

  • 谢谢大家,但现在我意识到问题在于标记化。

标签: c arrays numbers


【解决方案1】:

以下代码将一次读取一个文件一行

char line[80]
FILE* fp = fopen("data.txt","r");
while(fgets(line,1,fp) != null)
{
   // do something
}
fclose(fp);

然后您可以使用strtok()sscanf() 将输入标记化,以将文本转换为数字。

来自 sscanf 的 MSDN 页面:

这些函数 [sscanf 和 swscanf] 中的每一个都返回 成功的字段数 转换和分配;回报 值不包括以下字段 已读取但未分配。回报 值为 0 表示没有字段 被分配。返回值为EOF 对于错误或如果结束 字符串在第一个之前到达 转换。

以下代码会将字符串转换为整数数组。显然,对于可变长度数组,您需要一个列表或一些扫描输入两次以确定数组的长度,然后再实际解析它。

char tokenstring[] = "12 23 3 4 5";
char seps[] = " ";
char* token;
int var;
int input[5];
int i = 0;

token = strtok (tokenstring, seps);
while (token != NULL)
{
    sscanf (token, "%d", &var);
    input[i++] = var;

    token = strtok (NULL, seps);
}

推杆:

char seps[]   = " ,\t\n";

将使输入更加灵活。

我不得不进行搜索以提醒自己语法 - 我找到了 here in the MSDN

【讨论】:

  • 你能告诉我如何使用 sscanf() 来处理每行未知的总数,以便将其解析为数组吗?
  • @ChrisF 我在这里找到的想法是使用 int var 临时使用,顺便说一句,非常感谢。
  • @ChrisF 有没有办法让它处理 1,2,,4?
  • @cokedude - 自从我愤怒地完成 c 以来已经有一段时间了,所以我想我不能在这里帮助你。我确定有一个简单的解决方案!
【解决方案2】:

我会做这样的功能:

size_t read_em(FILE *f, int **a);

在函数中,为指针*a分配一些内存,然后开始从f中读取数字并将它们存储在*a中。当您遇到换行符时,只需返回您在*a 中存储的元素数。然后,这样称呼它:

int *a = NULL;
FILE *f = fopen("Somefile.txt", "r");
size_t len = read_em(f, &a);
// now a is an array, and len is the number of elements in that array

有用的功能:

  • malloc() 分配一个数组。
  • realloc() 扩展 malloc()ed 数组
  • fgets() 读取一行文本(或尽可能多的内容)。
  • sscanf() 将数据从字符串(例如fgets() 返回的字符串)读取到其他变量(例如malloc() 创建的int 数组 - 提示)

【讨论】:

    【解决方案3】:

    您的文件是否有特定数量的行,或者您是否需要能够将任意数字读入随机数组?

    这是逐行读取文件的代码。

    #include <stdio.h>
    
    int main()
    {
        char *inname = "test.txt";
        FILE *infile;
        char line_buffer[BUFSIZ];
    
        infile = fopen(inname, "r");
        if (!infile) {
            printf("Couldn't open file %s for reading.\n", inname);
            return 0;
        }
    
        while (fgets(line_buffer, sizeof(line_buffer), infile)) {
            // process line
        }
    
        return 0;
    }
    

    您可以使用sscanf 或许多标记化/转换函数中的任何一个来提取数字。 BUFSIZ 是来自 stdio.h 的一个很好的常量,旨在提高目标系统上的流 I/O 效率。

    【讨论】:

    • 为什么将line_number 存储为char 类型?您是否希望固有地限制为 127 行?
    • 你能告诉我如何使用 sscanf 提取数字吗?
    • line_number 甚至不应该在那里,它是来自其他一些代码的工件......现在已删除。
    【解决方案4】:

    我强烈建议不要在字段数量可变时使用 sscanf 和朋友。 使用strtokatoi。请务必仔细阅读 strtok 手册页,我认识的许多程序员在开始时发现它的语法有点令人惊讶。另请注意,strtok 将修改输入字符串,因此您可能需要处理副本。

    【讨论】:

    • 更好:使用strtol(),这样你就不需要strtok()
    【解决方案5】:

    以下代码可能是您要查找的内容。希望您不需要对 cme​​ts 进行太多描述,但如果您有任何问题,请随时提出。

    它基本上使用fgets 循环来读取每一行,并使用strtok 将该行分隔为字段。它构造了一个包含实际数据的整数数组的链表 - 您可以在最后转储表的代码中看到该链表的使用。

    它还有一种方法可以处理输入文件中任意大小的行,而不会出现缓冲区溢出(当然受内存限制)。请记住,strtok 只希望行上的每个字段之间有一个空格,尽管 可以 重新编码以处理多个空格甚至任何数量的空格。我一直保持简单,因为代码已经有点大了:-)

    atoi 函数用于将每行中的单个单词转换为整数。如果您想对这些进行错误检查,我会调用您自己的变体,它还会检查单词中的所有字符是否都是数字。

    使用您的输入文件:

    12 3 45 6 7 8
    3 5 6 7
    7 0 -1 4 5
    

    它产生的输出如下:

    0x97b5170, size = 6:
       12 3 45 6 7 8
    0x97b51d0, size = 4:
       3 5 6 7
    0x97b51e0, size = 5:
       7 0 -1 4 5
    

    这是产生该输出的代码:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <errno.h>
    
    // This is the linked list of integer arrays.
    
    typedef struct _tIntArray {
        int size;
        int *array;
        struct _tIntArray *next;
    } tIntArray;
    static tIntArray *first = NULL;
    static tIntArray *last = NULL;
    
    // Add a line of integers as a node.
    
    static int addNode (char *str) {
        tIntArray *curr;  // pointers for new integer array.
        char *word;       // word within string.
        char *tmpStr;     // temp copy of buffer.
        int fldCnt;       // field count for line.
        int i;
    
        // Count number of fields.
    
        if ((tmpStr = strdup (str)) == NULL) {
            printf ("Cannot allocate duplicate string (%d).\n", errno);
            return 1;
        }
        fldCnt = 0;
        for (word = strtok (tmpStr, " "); word; word = strtok (NULL, " "))
            fldCnt++;
        free (tmpStr);
    

     

        // Create new linked list node.
    
        if ((curr = malloc (sizeof (tIntArray))) == NULL) {
            printf ("Cannot allocate integer array node (%d).\n", errno);
            return 1;
        }
    
        curr->size = fldCnt;
        if ((curr->array = malloc (fldCnt * sizeof (int))) == NULL) {
            printf ("Cannot allocate integer array (%d).\n", errno);
            free (curr);
            return 1;
        }
        curr->next = NULL;
    
        for (i = 0, word = strtok (str, " "); word; word = strtok (NULL, " "))
            curr->array[i++] = atoi (word);
    
        if (last == NULL)
            first = last = curr;
        else {
            last->next = curr;
            last = curr;
        }
    
        return 0;
    }
    

     

    int main(void) {
        int lineSz;       // current line size.
        char *buff;       // buffer to hold line.
        FILE *fin;        // input file handle.
        long offset;      // offset for re-allocating line buffer.
        tIntArray *curr;  // pointers for new integer array.
        int i;
    
        // Open file.
    
        if ((fin = fopen ("qq.in", "r")) == NULL) {
            printf ("Cannot open qq.in, errno = %d\n", errno);
            return 1;
        }
    
        // Allocate initial line.
    
        lineSz = 2;
        if ((buff = malloc (lineSz+1)) == NULL) {
            printf ("Cannot allocate initial memory, errno = %d.\n", errno);
            return 1;
        }
    
        // Loop forever.
    
        while (1) {
            // Save offset in case we need to re-read.
    
            offset = ftell (fin);
    

     

            // Get line, exit if end of file.
    
            if (fgets (buff, lineSz, fin) == NULL)
                break;
    
            // If no newline, assume buffer wasn't big enough.
    
            if (buff[strlen(buff)-1] != '\n') {
                // Get bigger buffer and seek back to line start and retry.
    
                free (buff);
                lineSz += 3;
                if ((buff = malloc (lineSz+1)) == NULL) {
                    printf ("Cannot allocate extra memory, errno = %d.\n", errno);
                    return 1;
                }
                if (fseek (fin, offset, SEEK_SET) != 0) {
                    printf ("Cannot seek, errno = %d.\n", errno);
                    return 1;
                }
                continue;
            }
    
            // Remove newline and process.
    
            buff[strlen(buff)-1] = '\0';
            if (addNode (buff) != 0)
                return 1;
        }
    

     

        // Dump table for debugging.
    
        for (curr = first; curr != NULL; curr = curr->next) {
            printf ("%p, size = %d:\n  ", curr, curr->size);
            for (i = 0; i < curr->size; i++)
                printf (" %d", curr->array[i]);
            printf ("\n");
        }
    
        // Free resources and exit.
    
        free (buff);
        fclose (fin);
        return 0;
    }
    

    【讨论】:

      【解决方案6】:

      使用strtol()解析每一行:

      #include <errno.h>
      #include <stdio.h>
      #include <stdlib.h>
      
      int main(void)
      {
          static char buffer[1024];
          static long values[256];
      
          while(fgets(buffer, sizeof buffer, stdin))
          {
              char *current = buffer;
              size_t i = 0;
              while(*current && *current != '\n' &&
                  i < sizeof values / sizeof *values)
              {
                  char *tail = NULL;
                  errno = 0;
                  values[i] = strtol(current, &tail, 0);
      
                  if(errno || tail == current)
                  {
                      fprintf(stderr, "failed to parse %s\n", current);
                      break;
                  }
      
                  ++i, current = tail;
              }
      
              // process values
              printf("read %i values\n", i);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2011-11-29
        • 2016-11-14
        • 2023-03-16
        • 2015-10-14
        • 2015-02-07
        • 1970-01-01
        • 2017-08-25
        • 2011-01-06
        • 1970-01-01
        相关资源
        最近更新 更多