[英]Scanning variable number of 'fields' from a text file
我想掃描一個由空格分隔的文本文件構成矢量的變量,而絆腳石(對我而言,常常都是這樣)缺乏優雅。
目前,我的掃描代碼需要將向量的大小描繪為文件中的第一個元素:
7 : 1 3 6 8 -9 .123 1.1
這讓我感到困擾,因為可以通過檢查空白來確定“ 7”。
我已經嘗試過各種形式的fscanf(),strtok()等,但是似乎都蠻殘酷的。 如果不訴諸lex / yacc(不可用),有人會建議比以下更優雅的方法嗎?
typedef struct vector_tag
{
int Length;
double * value;
} vector;
vector v;
char buf[BIG_ENOUGH], key[BIG_ENOUGH], val[BIG_ENOUGH];
void scan_vector(FILE * fh)
{
int i, length;
double * data;
char * tok;
do {
if (feof(fh)) return;
fgets(buf, sizeof buf, fh);
} while (2 != sscanf(buf,"%[^:]:%[^\n\r]",key,val));
length =
v.Length = strtol(key,NULL,10);
data =
v.value = malloc(length * sizeof(double));
tok = strtok(val, " "); /* I'd prefer tokenizing on whitespace */
for (i = 0; i++ < v.Length; ) {
* data++ = strtod(tok,NULL);;
tok = strtok(NULL, " "); /* Again, tokenize on whitespace */
}
}
解決方案:由於選擇了答案,我實現了:
static int scan_vector(FILE * fh, vector * v)
{
if (1 == fscanf(fh,"%d:",& v->length))
{
int i;
v->value = malloc(v->Length * sizeof(double));
assert (NULL != v->value);
for (i = 0; i < v->Length; i++)
{
if (fscanf(fh,"%lf",v->value + i) != 1) return(0);
}
return(1);
}
return(0);
} /* scan_vector() */
諸如此類的問題是什么?
int scan_vector(FILE *fh)
{
char pad[2];
int i;
if (fscanf(fh,"%d %1[:]", &v.Length, &pad) != 2)
return -1;
v.value = malloc(v.Length * sizeof(double));
for (i = 0; i < v.Length; i++) {
if (fscanf(fh, "%lf", &v.value[i]) != 1)
return -1;
}
return 0;
}
這會嘗試使用scanf讀取向量,如果出現問題,則返回-1錯誤代碼。
如果您想做比這更復雜的事情,那么最好至少使用flex(如果不是野牛的話)。
如果使用realloc()
,如果初始malloc()
分配的內存不足,您總是可以請求更多的內存。 常見的策略是分配任意n
項目開始。 每當您用完空間時,就將n
加倍並調整緩沖區的大小。
或者,您可以使用鏈表而不是數組。 鏈接列表比數組更好地處理插入和追加,但是您放棄了按索引訪問項目的功能。
您的向量有多大?
一種方法是
如您所見,維度'7'
不必是輸入的一部分。
您只需要一個足夠大的本地緩沖區即可容納最長的行。
而且,它的一些錯誤處理:-)
這是一個不需要向量大小作為文件中第一項的版本:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define LINE_MAX 256
#define VECTOR_SIZE_MAX 32
struct vector
{
size_t size;
double *values;
};
// returns 1 on error
_Bool scan_vector(FILE *file, struct vector *v)
{
char buffer[LINE_MAX];
if(!fgets(buffer, sizeof(buffer), file))
return 1;
double values[VECTOR_SIZE_MAX];
size_t size = 0;
errno = 0;
for(char *head = buffer, *tail = NULL;; ++size, head = tail)
{
while(isspace(*head)) ++head;
if(!*head) break;
if(size >= VECTOR_SIZE_MAX)
return 1;
values[size] = strtod(head, &tail);
if(errno || head == tail)
return 1;
}
v->size = size;
v->values = malloc(sizeof(double) * size);
if(!v->values) return 1;
memcpy(v->values, values, sizeof(double) * size);
return 0;
}
int main(void)
{
struct vector v;
while(!scan_vector(stdin, &v))
{
printf("value count: %u\n", (unsigned)v.size);
free(v.values);
}
return 0;
}
由於性能原因和懶惰,最大行大小和條目數是固定的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.