[英]C parsing data from files
所以我試圖將文本文件中給出的一些數據解析為 C 程序。 文本文件包括:
4 4
1 1 0 0
1 1 0 0
0 0 1 1
0 0 1 1
前兩個數字是二維數組存儲整數所需的行數和長度。 到目前為止,我的代碼是:
file = fopen(argv[1], "r");
if (file == NULL)
{
perror("File IO error\n");
}
else
{
while(fgets(line, sizeof(line), file) != NULL)
{
if(sscanf(line, "%d %d %d %d", &a, &b, &c, &d) == 4)
{
printf("%d %d %d %d\n", a, b, c, d);
}
else
{
sscanf(line, "%d %d", &ROW, &COL);
printf("ROW: %d COL: %d\n", ROW, COL);
}
我遇到的問題是需要輸入其他文本文件。 它們與上面的行和列不同。 例如:
15 15
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 0 0 0 1 1 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 1 0 1 0 0 0 0 1 0
0 1 0 0 0 0 1 0 1 0 0 0 0 1 0
0 1 0 0 0 0 1 0 1 0 0 0 0 1 0
0 0 0 1 1 1 0 0 0 1 1 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 0 0 0 1 1 1 0 0 0
0 1 0 0 0 0 1 0 1 0 0 0 0 1 0
0 1 0 0 0 0 1 0 1 0 0 0 0 1 0
0 1 0 0 0 0 1 0 1 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 0 0 0 1 1 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
由於我的代碼每行僅適用於 4 個整數,因此它不適用於更大或更小的文件。 我將如何使其動態並根據大小進行解析。 謝謝
一次將數據讀取一個整數到緩沖區中。 如果您真的想要一個二維數組,您將不得不復制數據或注意前 2 個數據點並在讀取它們后分配數組。 但是,將數據流中的元素數量作為數據流前綴的做法是一種反模式,您並不真正想要二維數組。 您只希望能夠寫入data[i][j]
來訪問緩沖區中的數據,就好像它是一個二維數組一樣。 另外,不要打擾文件 I/O。 從輸入流中讀取並寫入輸出流並讓 shell 處理重定向。 (例如,代替cmd input-file
,執行cmd < input-file
)。 動態增加緩沖區是您應該練習的一項基本任務。 例如:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
struct int_buf {
int *data;
size_t cap;
size_t len;
};
void *xrealloc(void *b, size_t num, size_t siz);
static void
push(struct int_buf *b, int v)
{
while( b->cap <= b->len ){
b->data = xrealloc(b->data, b->cap += 128, sizeof *b->data);
}
b->data[b->len++] = v;
}
static void
die(const char *msg)
{
fputs(msg, stderr);
exit(EXIT_FAILURE);
}
int
main(int argc, char **argv)
{
struct int_buf b = {NULL, 0, 0};
int v;
int rows, columns;
if( scanf("%d %d", &rows, &columns) != 2 ){
die("invalid row/column count\n");
}
while( scanf("%d", &v) == 1 ){
push(&b, v);
}
if( ! feof(stdin) ){
die(ferror(stdin) ? "input error\n" : "invalid data\n");
}
if( b.len != rows * columns ){
die("inconsistent data\n");
}
int (*data)[columns] = (void *)b.data;
for( int r = 0; r < rows; r += 1 ){
printf(" row %3d: ", r);
for( int c = 0; c < columns; c += 1 ){
printf(" %3d", data[r][c]);
}
putchar('\n');
}
}
void *
xrealloc(void *b, size_t num, size_t siz)
{
b = realloc(b, num * siz);
if( b == NULL ){
perror("realloc");
exit(EXIT_FAILURE);
}
return b;
}
在此特定用例中,不需要前兩個數據點。 對於這個示例,我們使用了它們,這樣我們就不必擔心輸入流中的換行符,這樣我們就可以使用scanf
( scanf
是一個永遠不應該使用的糟糕工具,但這是一個不同的討論。這里我'會指出,在某些輸入上,上面的程序會表現出未定義的行為。你可以用"%12d"
或類似的東西來避免這種情況,但是你需要知道一個整數的最大大小來決定使用什么值。語言保證非常保守,因此除非您想動態構建格式字符串或生成特定於平台的代碼,否則您將不得不使用諸如%4d
之類的小得可笑的東西)。 我們可以像讀取流一樣輕松地計算換行符並丟棄前 2 個數據點。
如果您的文本文件已格式化。 你可以使用strtok
和strtol
#include<stdio.h>
#include<string.h>
#include <stdlib.h>
int main() {
char payload[] = {"1 2 3 4"};
char *token = strtok(payload, " ");
while (token) {
int v = (int)strtol(token,NULL,10);
printf("%d\n",v);
token = strtok(NULL, " ");
}
return 0;
}
您可以像這樣在循環中運行 scanf:
int rows, cols;
if(fscanf(file, "%d %d", &rows, &cols) != 2) {
// error
}
int num;
for(int i = 0; i<rows; ++i) {
for(int j = 0; j < (cols - 1); ++j) {
if(fscanf(file, "%d", &num) == 1) {
printf("%d ", num);
}
else { /* error */ }
}
if(fscanf(file, "%d", &num) == 1) {
printf("%d\n", num); // last col handled differently
}
else { /* error */ }
}
如果你想一次接收整行,你可以使用 int 數組(不需要字符串,就像你的例子一樣)
int* row = malloc(sizeof(int) * cols); // allocate memory for array
if(row == NULL) {/* error */}
for(int i = 0; i<rows; ++i) {
for(int j = 0; j < cols; ++j) {
if(fscanf(file, "%d", &row[j]) != 1) { /* error */}
}
// do what you want with your row
}
free(row); // release array memory
為了讀取具有不同行數和列數的文件,我建議您在讀取包含行數和列數的第一行后動態分配內存。
例子:
#include <stdio.h>
#include <stdlib.h> // malloc/free
int main(int argc, char* argv[]) {
if(argc != 2) return 1;
FILE *file = fopen(argv[1], "r");
if (file == NULL) {
perror("fopen");
return 1;
}
int ROW, COL;
if(fscanf(file, "%d %d", &ROW, &COL) != 2 || ROW < 1 || COL < 1) {
fprintf(stderr, "invalid file format\n");
return 1;
}
// allocate the needed memory to store the data:
int (*arr)[COL] = malloc(ROW * sizeof *arr);
if(arr == NULL) {
perror("malloc");
return 1;
}
// read the data from file into your dynamically allocated array:
for(int row = 0; row < ROW; ++row) {
for(int col = 0; col < COL; ++col) {
if(fscanf(file, " %d", &arr[row][col]) != 1) {
fprintf(stderr, "invalid file format\n");
fclose(file);
free(arr);
return 1;
}
}
}
fclose(file);
// display the result:
printf("ROW: %d COL: %d\n", ROW, COL);
for(int row = 0; row < ROW; ++row) {
for(int col = 0; col < COL; ++col) {
printf("%d ", arr[row][col]);
}
putchar('\n');
}
free(arr); // release the memory allocated dynamically
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.