我试图解析一组具有相同格式的文件。下面是一个例子:
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新手!)
不管怎样,我的代码不工作。具体来说,我通过使用调试器注意到它没有提升矩阵的维度,这意味着正确读取矩阵的尝试从一开始就注定要失败。所有变量都声明了,这不是问题。它只是没有在维度之后读取数字并将其赋值给size。我做错了什么?
编辑:我已经尝试了Vicky对fscanf(fp, "%sn", buf);
的建议-它也有让我通过观察buf的值来查看它在文件中的位置的优点-并发现它一次取一个词,而不是一行。这种方法的问题在于COMMENT:行所包含的字数不一致。使用"%*s"
和"%*sn"
没有写任何东西,但是
编辑2:while((c = getchar()) != 'n' && c != 'EOF') ;
只是挂起程序。不知道它在干什么。
编辑3:while((c = getc(fp)) != 'n' && c != 'EOF') ;
正在逐行浏览文件,但fscanf(fp, "%d", &size);
仍然没有拾取数字。
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') ;
}
谢谢大家的帮助!
我总是发现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;
}
}
}
这应该会给你一些想法,你当然可以添加更多的错误检查
仅计算n
来确定行结束是不可靠的,如果您的文件有r
作为行结束字符怎么办?事实上,您需要考虑n
, r
和rn
作为行结束序列。
Windows记事本是一种"Hello World"编辑器。它是非常基本和有限的,只能处理rn
作为行结束,这就是为什么如果行以r
或n
结束,它会显示单行。
C
中的行读取不是一项微不足道的任务,如果您知道一行的最大长度,则可以使用fgets,这样您就可以传递适当分配的缓冲区。否则,您将不得不处理未知的行长度,例如COMMENT
行。我个人更喜欢巫婆可以处理所有这些,并且在一次调用中只返回文件中的一行,参见这样的read_line函数的示例。
在文件格式中,矩阵的大小出现在第4行。因此必须转义到前三行,只需执行以下三次
read_line(pf);
在第4个read_line
上,您有包含大小的行。您需要提取并保存它以供以后使用。
// DIMENSION: 17
line = read_line(pf);
printf("%sn", line);
// extact the size of the matrix
tmp = strtok(line, " ");
tmp = strtok(NULL, " ");
size = atoi(tmp);
printf("Parsed size = %dn", size);
free(line);
line_number++;
现在你还有另外三行来组成你的矩阵。像第一个一样转义它们。
现在你的矩阵开始了,这里你可以使用fscanf
,你可以在你分配一个矩阵行之后开始从文件中读取,这样你可以节省一些不必要的迭代。
下面是构建循环的方法:
if(size > 0) {
printf("Start reaading matrix of size %dx%dnn", 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("%.2lft", matrix[i][j]);
}
printf("n");
line_number++;
if(n_read != size) {
printf("invalid data at line %d, expected to read %d but got %dn", line_number, size, n_read);
}
}
}