-1

我正在尝试解析一组格式相同的文件。这是一个示例:

NAME:  br17
TYPE: ATSP
COMMENT: 17 city problem (Repetto)
DIMENSION:  17
EDGE_WEIGHT_TYPE: EXPLICIT
EDGE_WEIGHT_FORMAT: FULL_MATRIX 
EDGE_WEIGHT_SECTION
 9999    3    5   48   48    8    8    5    5    3    3    0    3    5    8    8
    5
    3 9999    3   48   48    8    8    5    5    0    0    3    0    3    8    8
    5
    5    3 9999   72   72   48   48   24   24    3    3    5    3    0   48   48
   24
   48   48   74 9999    0    6    6   12   12   48   48   48   48   74    6    6
   12
   48   48   74    0 9999    6    6   12   12   48   48   48   48   74    6    6
   12
    8    8   50    6    6 9999    0    8    8    8    8    8    8   50    0    0
    8
    8    8   50    6    6    0 9999    8    8    8    8    8    8   50    0    0
    8
    5    5   26   12   12    8    8 9999    0    5    5    5    5   26    8    8
    0
    5    5   26   12   12    8    8    0 9999    5    5    5    5   26    8    8
    0
    3    0    3   48   48    8    8    5    5 9999    0    3    0    3    8    8
    5
    3    0    3   48   48    8    8    5    5    0 9999    3    0    3    8    8
    5
    0    3    5   48   48    8    8    5    5    3    3 9999    3    5    8    8
    5
    3    0    3   48   48    8    8    5    5    0    0    3 9999    3    8    8
    5
    5    3    0   72   72   48   48   24   24    3    3    5    3 9999   48   48
   24
    8    8   50    6    6    0    0    8    8    8    8    8    8   50 9999    0
    8
    8    8   50    6    6    0    0    8    8    8    8    8    8   50    0 9999
    8
    5    5   26   12   12    8    8    0    0    5    5    5    5   26    8    8
 9999
EOF

我想提升矩阵的维度和矩阵本身,其他一切都可以丢弃。这是我目前用来尝试解析它的代码:

fp = fopen(argv[1] , "r");

for (i = 0; i < 3; ++i)
{
    fscanf(fp, "\n");
}
fscanf(fp, "%d", &size);
for (i = 0; i < 3; ++i)
{
    fscanf(fp, "\n");
}
cost = (double**) calloc(size, sizeof(double*));
for(i = 0 ; i < size; ++i){
    cost[i] = (double*) calloc(size, sizeof(double));
}

for(i = 0 ; i < size; ++i)
{
    for(j = 0 ; j < size; ++j)
    {
        fscanf(fp, "%lf", &(cost[i][j]));
    }
    cost[i][i] = 0;
}

fclose(fp);

(当我在文本编辑器中打开该文件时,它似乎确实有换行符 - 虽然不是在记事本中 - 我不知道它们为什么在这里消失了。NAME、TYPE、COMMENT、DIMENSION、EDGE_WEIGHT_TYPE、EDGE_WEIGHT_FORMAT 和 EDGE_WEIGHT_SECTION 都会出现开始新行。编辑:啊,谢谢,约塞连。我是 Stack Overflow 新手!)

无论如何,我的代码不起作用。具体来说,我通过使用调试器注意到它并没有提升矩阵的维度,这意味着正确读取矩阵的尝试从一开始就注定要失败。所有变量都已声明,这不是问题。它只是不读取尺寸后的数字并将其分配给尺寸。我究竟做错了什么?

编辑:我已经尝试了 Vicky 的建议fscanf(fp, "%s\n", buf);——它还有一个优点是让我通过观察 buf 的值来查看它在文件中的位置——并发现它一次只占用一个单词,而不是一行。这种方法的问题在于 COMMENT: 行的字数不一致。使用"%*s"并且"%*s\n"根本没有写任何东西给 buf。

编辑2:while((c = getchar()) != '\n' && c != 'EOF') ;只是挂起程序。不知道它在做什么。

编辑3:while((c = getc(fp)) != '\n' && c != 'EOF') ;正在逐行浏览文件,但fscanf(fp, "%d", &size);仍然没有收到号码。

编辑4:啊哈!得到它的工作

char c; 
for (i = 0; i < 3; ++i)
{
    while((c = getc(fp)) != '\n' && c != 'EOF') ;
}
fscanf(fp, "%*s");
fscanf(fp, "%i", &size);

for (i = 0; i < 4; ++i)
{
    while((c = getc(fp)) != '\n' && c != 'EOF') ;
}

谢谢大家的帮助!

4

2 回答 2

1

我总是发现 scanf 函数带来的问题比它们解决的问题多。

就个人而言,我更喜欢使用 fgets:-

char buffer [1024];
file = fopen (filename);

while (fgets (buffer, 1024, file))
{
  ParseState state = FindingLineType;

  for (char *token = strtok (buffer, " ") ; token ; token = strtok (0, " "))
  {
    // parse the token!
    switch (state)
    {
    case FindingLineType:
      if (stricmp (token, "DIMENSION:") == 0)
      {
        state = GettingDimension;
      }
      else
      {
        if (isdigit (*token))
        {
          if matrix has been created
          {
            state = ParsingMatrix;
          }
          else
          {
            error - got matrix row before dimension
          }
        }
      }
      break;

    case GettingDimension:
      dimension = atoi (token);
      create matrix
      break;
    }
  }
}

那应该会给你一些想法,你当然可以添加更多的错误检查。

于 2013-05-09T10:25:13.797 回答
0

仅依靠\n确定行结束是不可靠的,如果您的文件具有\r 行终止字符怎么办?实际上,您需要考虑\n,\r\r\n作为行尾序列。

Windows 记事本是一种“Hello World”编辑器。它非常基本且有限,只能作为行结尾处理,这就是为什么如果行以or\r\n结尾,它会显示一行。\r\n

读入行C不是一项简单的任务,如果您知道一行最多可以有多长,则可以使用fgets ,这样您就可以传递一个适当分配的缓冲区。否则你将不得不处理未知的线路长度,女巫就是你的COMMENT线路。我个人更喜欢让女巫可以处理所有这些,并且只需在一次调用中从文件中返回一行,请参阅此类read_line函数的示例。

在文件格式中,您在第 4 行显示了矩阵的大小。因此必须转义到前三行,只需执行以下三遍

read_line(pf);

在 4 日read_line,您有包含大小的行。您需要提取并保存以供以后使用。

// DIMENSION:  17
line = read_line(pf);
printf("%s\n", line);
// extact the size of the matrix
tmp = strtok(line, " ");
tmp = strtok(NULL, " ");
size = atoi(tmp);
printf("Parsed size = %d\n", size);
free(line);
line_number++;

现在你还有另外三行可以进入你的矩阵。像第一个一样逃离他们。

现在你的矩阵开始了,你可以在这里使用fscanf,你可以在分配矩阵行后立即开始从文件中读取,这样你就可以节省一些不必要的迭代。

以下是构建循环的方法:

if(size > 0) {
    printf("Start reaading matrix of size %dx%d\n\n", size, size);
    matrix = malloc(sizeof(double*) * size);
    for(i = 0; i < size; i++) {
        matrix[i] = malloc(sizeof(double) * size);

        n_read = 0;
        for(j = 0; j < size; j++) {
            n_read += fscanf(pf, "%lf", &matrix[i][j]);
            printf("%.2lf\t", matrix[i][j]);
        }
        printf("\n");
        line_number++;
        if(n_read != size) {
            printf("invalid data at line %d, expected to read %d but got %d\n", line_number, size, n_read);
        }
    }
}
于 2013-05-09T10:52:07.123 回答