0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

TSV,CSV形式のファイルから二次元配列を読み取る

0
Posted at

タブ区切り(TSV)形式、カンマ区切り(CSV)形式の数値ファイルを読み取るプログラムを作ります。いろいろと汎用性が高いものになっています。

二次元配列のクラス作成

二次元配列とその行数、列数の情報をまとめて扱う二次元配列のクラスを作成します。命名法を工夫するだけでオブジェクト指向ができるC言語のオブジェクト指向的な記法を使います。

構造体を定義して、そのポインタをtypedefします。構造体を操作する関数(メソッド)は必ずtypedefした構造体のポインタを第一引数として受け取ります。コンストラクタはクラス名_create クラス名_deleteとします。

Array2D.h
typedef struct st_array2d{
	int rows;
	int columns;
	double **data;
}Array2D_Sub;
typedef struct st_array2d *Array2D;

Array2D Array2D_create(int rows, int columns);
void Array2D_delete(Array2D array);
void Array2D_fprint(Array2D array, FILE *fp,char *sep);
void Array2D_print(Array2D array, char *file,char *sep);
//後で実装
Array2D Array2D_read(char *string, ReadOptions options);
`Array2D.c`
Array2D.c
# include "Array2D.h"
Array2D Array2D_create(int rows, int columns){
	Array2D array = malloc(sizeof(Array2D_Sub));
	Array2D_init(array,rows,columns);
	return array;
}
void Array2D_delete(Array2D array){
	Array2D_finish(array);
	free(array);
}
void Array2D_fprint(Array2D array, FILE *fp, char *sep){
	int i,j;
	for(i=0;i<array->row;i++){
		for(j=0;j<array->column;j++){
			fprintf(fp,"%g%s",array->data[i][j],sep);
		}
		fprintf(fp,"\n");
	}
}
void Array2D_print(Array2D array, char *file, char *sep){
	FILE *fp;
	
	fp = fopen(file,"w");
	if(!fp){
		perror("Array2D_print : ");
		return;
	}
	Array2D_fprint(array,fp,sep);
	fclose(fp);
}
## 読み取りオプションの構造体作成 テキストファイルを読み取るときに、いろんなオプションを指定できるようにします。オプションをまとめた構造体`ReadOption`を作ってこれをファイル読み取り関数`Array2D_read`に渡します。
Array2D Array2D_read(char *string, ReadOption option);

構造体 ReadOptions

# define AUTO -1
# define TRUE 1
# define FALSE 0

typedef struct st_readoptions{
	int rows;
	int columns;
	int rowOffset;
	int columnOffset;
	char **lineSeparators;
	int lineSeparatorsCount;
	char **fieldSeparators;
	int fieldSeparatorsCount;
	int repeatedSeparators;
	int ignoreEmptyLines;
}ReadOptions_Sub;
typedef struct st_readoptions *ReadOptions;

ReadOptionsの各オプションの意味と初期値は以下の表のようになります。

データ型 変数名 意味 初期値
int rows 行数 AUTO (-1)
int columns 列数 AUTO (-1)
int rowOffset 読み取り開始行 0
int columnOffset 読み取り開始列 0
char** lineSeparators 行区切り文字の配列 NULL
int lineSeparatorsCount 指定する行区切り文字の個数 0
char** fieldSeparators 列区切り文字の配列 NULL
int fieldSeparatorsCount 指定する列区切り文字の個数 0
int repeatedSeparators 連続する区切り文字を無視 TRUE(1)
int ignoreEmptyLines 空白行無視 TRUE(1)

ReadOptionsのメソッド

stdarg.hを使って可変長引数関数にします。(C言語 可変長引数関数について 【初心者向け】)

Array2D.h
typedef struct st_array2d{
	int rows;
	int columns;
	double **data;
}Array2D_Sub;
typedef struct st_array2d *Array2D;

Array2D Array2D_create(int rows, int columns);
void Array2D_delete(Array2D array);
void Array2D_fprint(Array2D array, FILE *fp,char *sep);
void Array2D_print(Array2D array, char *file,char *sep);
//後で実装
Array2D Array2D_read(char *string, ReadOptions options);

# define AUTO -1
# define TRUE 1
# define FALSE 0
# include <stdarg.h>
void ReadOptions_init(ReadOptions options);
void ReadOptions_finish(ReadOptions options);
void ReadOptions_print(ReadOptions options);
void ReadOptions_setLineSeparators(ReadOptions options, int lineSeparatorsCount, ...);
void ReadOptions_setFieldSeparators(ReadOptions options, int fieldSeparatorsCount, ...);
`Array2D.c`
Array2D.c
Array2D Array2D_create(int rows, int columns){
	Array2D array = malloc(sizeof(Array2D_Sub));
	Array2D_init(array,rows,columns);
	return array;
}
void Array2D_delete(Array2D array){
	Array2D_finish(array);
	free(array);
}
void Array2D_init(Array2D array, int rows, int columns){
	int i,j;
	array->rows = rows;
	array->columns = columns;
	array->data = malloc(rows*sizeof(double*));
	array->data[0] = malloc(rows*columns*sizeof(double));
	for(i=0;i<rows;i++){
		array->data[i] = &(array->data[0][i*columns]);
		for(j=0;j<columns;j++){
			array->data[i][j] = 0;
		}
	}
}
void Array2D_fprint(Array2D array, FILE *fp, char *sep){
	int i,j;
	for(i=0;i<array->row;i++){
		for(j=0;j<array->column;j++){
			fprintf(fp,"%g%s",array->data[i][j],sep);
		}
		fprintf(fp,"\n");
	}
}
void Array2D_print(Array2D array, char *file, char *sep){
	FILE *fp;
	
	fp = fopen(file,"w");
	if(!fp){
		perror("Array2D_print : ");
		return;
	}
	Array2D_fprint(array,fp,sep);
	fclose(fp);
}

void ReadOptions_init(ReadOptions options){
	options->rows = AUTO;
	options->columns = AUTO;
	options->rowOffset = 0;
	options->columnOffset = 0;
	options->lineSeparators = NULL;
	options->lineSeparatorsCount = 0;
	options->fieldSeparators = NULL;
	options->fieldSeparatorsCount = 0;
	options->repeatedSeparators = TRUE;
	options->ignoreEmptyLines = FALSE;
}
void ReadOptions_finish(ReadOptions options){
	free(options->lineSeparators);
	free(options->fieldSeparators);
}

void ReadOptions_setLineSeparators(ReadOptions options, int lineSeparatorsCount, ...){
	int i;
	va_list list;
	
	options->lineSeparatorsCount = lineSeparatorsCount;
	options->lineSeparators = malloc(lineSeparatorsCount*sizeof(char*));
	va_start(list,lineSeparatorsCount);
	for(i=0;i<lineSeparatorsCount;i++){
		options->lineSeparators[i] = va_arg(list,char*);
	}
	va_end(list);
}

void ReadOptions_setFieldSeparators(ReadOptions options, int fieldSeparatorsCount, ...){
	int i;
	va_list list;
	
	options->fieldSeparatorsCount = fieldSeparatorsCount;
	options->fieldSeparators = malloc(fieldSeparatorsCount*sizeof(char*));
	va_start(list,fieldSeparatorsCount);
	for(i=0;i<fieldSeparatorsCount;i++){
		options->fieldSeparators[i] = va_arg(list,char*);
	}
	va_end(list);
}
void ReadOptions_print(ReadOptions options){
	int i;
	char *p;
	printf("rows : ");
	if(options->rows < 0){printf("Automatic\n");}
	else{printf("%d\n",options->rows);}
	printf("columns : ");
	if(options->columns < 0){printf("Automatic\n");}
	else{printf("%d\n",options->columns);}
	
	printf("row offset : %d\n",options->rowOffset);
	printf("column offset : %d\n",options->columnOffset);
	printf("line separators : ");
	printf("{");
	for(i=0;i<options->lineSeparatorsCount;i++){
		if(i>0){printf(",");}
		for(p=options->lineSeparators[i];*p;p++){
			switch(*p){
			  case '\r': printf("\\r"); break;
			  case '\n': printf("\\n"); break;
			  case '\t': printf("\\t"); break;
			  default: putchar(*p);
			}
		}
	}
	printf("}\n");
	printf("field separators : ");
	printf("{");
	for(i=0;i<options->fieldSeparatorsCount;i++){
		if(i>0){printf(",");}
		for(p=options->fieldSeparators[i];*p;p++){
			switch(*p){
			  case '\r': printf("\\r"); break;
			  case '\n': printf("\\n"); break;
			  case '\t': printf("\\t"); break;
			  default: putchar(*p);
			}
		}
	}
	printf("}\n");
	printf("repeatedSeparators : ");
	if(options->repeatedSeparators == TRUE){
		printf("True\n");
	}else{
		printf("False\n");
	}
	printf("ignoreEmptyLines : ");
	if(options->ignoreEmptyLines == TRUE){
		printf("True\n");
	}else{
		printf("False\n");
	}
}

ReadOptionsのテストコード

ReadOptions_test.c
# include "Array2D.h"
int main(int argc, char *argv[]){
	ReadOptions_Sub options;
	
	ReadOptions_init(&options);
	ReadOptions_setLineSeparators(&options,3,"\r","\r\n","\n");
	ReadOptions_setFieldSeparators(&options,3," ","\t");
	ReadOptions_print(&options);
	ReadOptions_finish(&options);
}

Array2D.hの予定される使い方

例:CSVファイルの3行目の4列目から2列のデータを読み取る。

ReadCSV.c
# include "Array2D.h"
int main(int argc, char *argv[]){
    char filein[256],*str;
    Array2D array;
    ReadOptions_Sub options;

    if(argc >= 2){
	strncpy(filein,argv[1],256);
    }
    str=String_read(filein);

    ReadOptions_init(&options);
    ReadOptions_setLineSeparators(&options,3,"\n","\r\n","\r"); 
    ReadOptions_setFieldSeparators(&options,1,",");
    options.rowOffset = 3;
    options.columnOffset = 4; 
    options.columns = 2;
    array=Array2D_read(str,&options);
}
`String_read`
# include <sys/stat.h>
unsigned long getFileSize(FILE *fp){
	unsigned long fsize = ftell(fp);
	fpos_t p; 
	fgetpos(fp,&p);
	fseek(fp,0,SEEK_END);
	fsize = ftell(fp) - fsize;
	fsetpos(fp,&p);
	return (unsigned long)fsize;
} 

char *String_fread(FILE *fp){
	char *buf;
	char c; unsigned long size;
	size = getFileSize(fp);
	buf = malloc(size+1);
	fread(buf,1,size,fp); buf[size] = '\0';
	return buf;
}

char *String_read(char *file){
	FILE *fp;
	char *str;
	fp = fopen(file,"r");
	if(!fp){perror("String_read"); return NULL;}
	str = String_fread(fp);
	fclose(fp);
	return str;
}

リスト構造

文字列を分割してリスト構造に保存します。
ここで作るStringListクラスは文字列のポインタを内容としてもつリスト構造で、リストを削除するとき文字列自体は消去しません。

StringListクラス

StringList.h
typedef struct st_stringlist *StringList;
typedef struct st_stringlist{
	char *string;
	StringList next;
}StringList_Sub;

StringList StringList_create(char *string);
void StringList_delete(StringList list);
void StringList_deleteRoot(StringList list);
StringList StringList_append(StringList list,char *string);
StringList StringList_last(StringList list);
StringList StringList_skip(StringList list, int k);
int StringList_length(StringList list);
StringList StringList_print(StringList list);
char **StringList_toArray(StringList list);
//後で実装
StringList StringList_splitString(char *string, char **separators, int separatorsCount, int repeatedSeparators);
`StringList.c`
StringList.c
# include "StringList.h"
StringList StringList_create(char *string){
	StringList list;
	list = malloc(sizeof(StringList_Sub));
	list->string = string;
	list->next = NULL;
	return list;
}

void StringList_delete(StringList list){free(list);}
void StringList_deleteRoot(StringList list){
	if(list){StringList_deleteRoot(list->next);};
	StringList_delete(list);
}

StringList StringList_last(StringList list){
	for(;list->next;list=list->next){}
	return list;
}

StringList StringList_append(StringList list,char *string){
	if(list){
		StringList_last(list)->next = StringList_create(string);
		return list;
	}else{
		return StringList_create(string);
	}
}

StringList StringList_skip(StringList list, int k){
	int i;
	for(i=0;i<k && list;list=list->next,i++){}
	return list;
}

StringList StringList_print(StringList list){
	if(list){
		for(;list;list=list->next){
			printf("%s\n",list->string);
		}
	}
}

int StringList_length(StringList list){
	int count=0;
	for(;list;list=list->next){count++;}
	return count;
}

char **StringList_toArray(StringList list){
	int i,len;
	char **array;
	len = StringList_length(list);
	array = malloc(len*sizeof(char*));
	for(i=0;i<len;i++,list++){
		array[i] = list->string;
	}
}

StringListのテストコード

StringList_test.c
# include "StringList.h"
int main(int argc, char *argv[]){
	StringList sl = StringList_create("ant");
	StringList_append(sl,"bear");
	StringList_append(sl,"cat");
	printf("length:%d\n",StringList_length(sl));
	StringList_print(sl);
	StringList_deleteRoot(sl);
}	

StringList_splitString

区切り文字によって文字列を分割する関数を作ります。

StringList.h
StringList StringList_splitString(char *string, char **separators, int separatorsCount, int repeatedSeparators);

stringはもとの文字列、separatorsは区切り文字のリスト、separatorsCountは区切り文字の数、repeatedSeparatorsは連続する区切り文字を無視するかどうかのフラグです。
仕様としてこの関数は、入力の文字列に対して区切り文字がある位置を\0で入れ替えるという破壊的処理を行います。なので入力の文字列は必ずmallocなどでメモリ上に確保した領域上のものである必要があります。
分割された文字列のメモリをいちいち確保するのは非効率なので、このような仕様にしました。

StringList.c
StringList StringList_splitString(char *string, char **separators, int separatorsCount,int repeatedSeparators){
	int i,imin,len;
	char *p,*p2,*last,*pmin;
	StringList list=NULL;

	/*文字列の最後尾のポインタをlastに保存*/
	last = strchr(string,'\0'); 
	/*ポインタpをstringの先頭から最後尾lastまで移動させていく*/
	/*p2が新しい位置*/
	for(p=string;p<last;p=p2){
		/*区切り文字の数だけ繰り返す*/
		for(i=0,pmin=last,imin=-1;i<separatorsCount;i++){
			/*区切り文字を検索して、p2にその位置を保存*/
			p2=strstr(p,separators[i]);
			/*区切り文字がない場合p2にはNULLが入る*/
			if(p2){
				/*見つかった区切り文字のうち、最も検索開始位置に近い位置を記憶*/
				if(p2 < pmin){
					imin = i;
					pmin = p2;
				}
			}
		}
		/*p2は次の検索の開始点となる。*/
		if(imin<0){
			/*区切り文字がみつからなかった場合。*/
			p2 = last;
		}else{
			/*区切り文字がみつかった場合*/
			len = strlen(separators[imin]);
			/*区切り文字を\0で置き換える*/
			for(i=0;i<len;i++){pmin[i] = '\0';}
			/*区切り文字の次の文字列をp2にいれる。*/
			p2 = &pmin[i];
		}
		/*pが\0でないか、repeatedSeparators==FALSEのときリストに文字列を追加する。*/
		/*repeatedSeparators==FALSEのとき、リストには空文字\0が入る。*/
		if(*p || !repeatedSeparators){list=StringList_append(list,p);}
	}
	return list;
}

Array2D_read

ファイルから二次元データを読み取る関数です。

Array2D.c
Array2D Array2D_read(char *string, ReadOptions options){
	StringList list,s,*listlist;
	int i,j,rows,columns,rofs,cofs,c;
	Array2D array=NULL;
	
	/*まず行区切り文字で分割する。*/
	list = StringList_splitString(string,options->lineSeparators,options->lineSeparatorsCount,options->ignoreEmptyLines);
	rows = StringList_length(list);
	
	/*行オフセットにマイナスの値を入れたらオフセットは_最後尾から数える。*/
	if(options->rowOffset < 0){
		rofs = rows + options->rowOffset;
	}else{
		rofs = options->rowOffset;
	}
	
	/*行数にマイナスの値を入れたら全行読み取る*/
	if(options->rows < 0){
		if(rows < rofs){
			printf("Array2D_read : row offset %d exceeds the row count %d\n",rofs,rows);
			goto end;
		}
		rows = rows - rofs;
	}else{
		if(rows < options->rows + rofs){
			printf("Array2D_read : rows %d + row offset %d exceeds input data rows %d\n",
				   options->rows,rofs,rows);
		}
		rows = options->rows;
	}

	/*行数ぶんのStringList配列を確保する。*/
	listlist = malloc(rows*sizeof(StringList));
	for(i=0,columns=0,s=StringList_skip(list,rofs);i<rows && s;i++,s=s->next){
		/*各行について、列区切り文字で分割する。*/
		listlist[i] = StringList_splitString(s->string,options->fieldSeparators,options->fieldSeparatorsCount,options->repeatedSeparators);
		/*最大の列数をcに格納する*/
		c = StringList_length(listlist[i]);
		if(columns < c){columns=c;}
	}
	
	/*列数、列オフセットについても行と同じ処理を行う。*/
	if(options->columnOffset < 0){
		cofs = columns + options->columnOffset;
	}else{
		cofs = options->columnOffset;
	}
	
	if(options->columns < 0){
		if(columns < cofs){
			printf("Array2D_read : column offset %d exceeds the input data columns%d\n",cofs,columns);
			goto end;
		}
		columns = columns - cofs;
	}else{
		if(columns < options->columns + cofs){
			printf("Array2D_read : columns %d + column offset %d exceeds input data columns %d\n",
				   options->columns,cofs,columns);
		}
		columns = options->columns;
	}
	
	array = Array2D_create(rows,columns);
	
	for(i=0;i<rows;i++){
		/*列オフセットだけリストをスキップする*/
		for(j=0,s=StringList_skip(listlist[i],cofs);j<columns && s;j++,s=s->next){
			array->data[i][j] = atof(s->string);
		}
	}
  end:
	/*リストを削除する。*/
	for(i=0;i<rows;i++){StringList_deleteRoot(listlist[i]);}
	free(listlist);
	StringList_deleteRoot(list);
	
	return array;
}

ファイルから二次元配列を読み取るプログラム

これまで作ったクラスを使って目的のプログラムを完成させます。
ファイルから配列を読み取って表示するだけのわりに、汎用性を高めてあるのでわりとボリューム感があります。
完成です。ありがとうございました。

readmat.c
# include "utilities.h"
# include "Array2D.h"
# include "StringList.h"
# include <getopt.h>

int main(int argc, char *argv[]){
	char filein[256],fileout[256],*str;
	int mode=0;
	int ch,len;
	extern char *optarg;
	extern int optind;
	
	Array2D array;
	StringList l_list=NULL,f_list=NULL;
	ReadOptions_Sub options;
	
	ReadOptions_init(&options);
	struct option longopts[]=
			{
			 {"rofs",required_argument,NULL,'r'},
			 {"cofs",required_argument,NULL,'c'},
			 {"row",required_argument,NULL,'R'},
			 {"col",required_argument,NULL,'C'},
			 {"rsep",required_argument,NULL,'l'},
			 {"csep",required_argument,NULL,'f'},
			 {0,0,0,0}
			 };
	int opt,longindex;
	
	while((opt=getopt_long(argc,argv,"r:c:R:C:l:f:",longopts,&longindex))!=-1){
		switch(opt){
		  case 'R':
			options.rowOffset = atoi(optarg); break;
		  case 'C':
			options.columnOffset = atoi(optarg); break;
		  case 'r':
			options.rows = atoi(optarg); break;
		  case 'c':
			options.columns = atoi(optarg); break;
		  case 'l':
			l_list = StringList_append(l_list,optarg); break;
		  case 'f':
			f_list = StringList_append(f_list,optarg); break;
		  default:
			break;
		}
	}
	
	if(optind < argc){
		strncpy(filein,argv[optind],256);
	}else{
		puts("input file name");
		readFromStdin(filein,256);
	}
	
	str=String_read(filein);
	if(l_list){
		options.lineSeparatorsCount = StringList_length(l_list);
		options.lineSeparators = StringList_toArray(l_list);
	}else{
		ReadOptions_setLineSeparators(&options,3,"\n","\r\n","\r");
	}
	if(f_list){
		options.fieldSeparatorsCount = StringList_length(f_list);
		options.fieldSeparators = StringList_toArray(f_list);
	}else{
		ReadOptions_setFieldSeparators(&options,2," ","\t");
	}
	StringList_delete(f_list);
	StringList_delete(l_list);
	
	//ReadOptions_print(&options);
	array=Array2D_read(str,&options);
	//printf("array->rows : %d\n",array->rows);
	//printf("array->columns : %d\n",array->columns);
	Array2D_fprint(array,stdout," ");
	Array2D_delete(array);
	ReadOptions_finish(&options);
	String_delete(str);
	return 0;
}

utilities.h
# ifndef UTILITIES_H
# define UTILITIES_H
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <sys/stat.h>
int readFromStdin(char *str,int size);
unsigned long getFileSize(FILE *fp);
char *String_fread(FILE *fp);
char *String_read(char *file);
void *String_delete(char *str);
# endif
`utilities.c`
utilities.c
# include "utilities.h"

unsigned long getFileSizeBin(const char *filename){
	struct stat st;
	if(stat(filename,&st)==0){return (unsigned long)st.st_size;}
	return 0;
}

unsigned long getFileSize(FILE *fp){
	unsigned long fsize = ftell(fp);
	fpos_t p; 
	fgetpos(fp,&p);
	fseek(fp,0,SEEK_END);
	fsize = ftell(fp) - fsize;
	fsetpos(fp,&p);
	return (unsigned long)fsize;
} 

char *String_fread(FILE *fp){
	char *buf;
	char c; unsigned long size;
	size = getFileSize(fp);
	buf = malloc(size+1);
	fread(buf,1,size,fp); buf[size] = '\0';
	return buf;
}

char *String_read(char *file){
	FILE *fp;
	char *str;
	fp = fopen(file,"r");
	if(!fp){perror("String_read"); return NULL;}
	str = String_fread(fp);
	fclose(fp);
	return str;
}

void *String_delete(char *str){free(str);}

int readFromStdin(char *str,int size){
	int len;
	fgets(str,size,stdin);
	len=strlen(str);
	if(str[len-1] != '\n'){
		scanf("%*s");
		return -1;
	}else{
		str[len-1]='\0';
	}
	return len;
}
Array2D.h
# ifndef ARRAY2D_H
# define ARRAY2D_H
# include <stdio.h>
# include <stdlib.h>
# include <ctype.h>
# include <string.h>
# include <stdarg.h>
# include <math.h>

# define AUTO -1
# define TRUE 1
# define FALSE 0

typedef struct st_array2d{
	int rows;
	int columns;
	double **data;
}Array2D_Sub;
typedef struct st_array2d *Array2D;

typedef struct st_readoptions{
	int rows;
	int columns;
	int rowOffset;
	int columnOffset;
	char **lineSeparators;
	int lineSeparatorsCount;
	char **fieldSeparators;
	int fieldSeparatorsCount;
	int repeatedSeparators;
	int ignoreEmptyLines;
}ReadOptions_Sub;
typedef struct st_readoptions *ReadOptions;

Array2D Array2D_create(int rows, int coulmns);
void Array2D_delete(Array2D array);
void Array2D_fprint(Array2D array, FILE *fp,char *sep);
void Array2D_print(Array2D array, char *file,char *sep);
Array2D Array2D_read(char *string, ReadOptions option);

void ReadOptions_init(ReadOptions options);
void ReadOptions_finish(ReadOptions options);
void ReadOptions_print(ReadOptions options);
void ReadOptions_setLineSeparators(ReadOptions options, int lineSeparatorsCount, ...);
void ReadOptions_setFieldSeparators(ReadOptions options, int fieldSeparatorsCount, ...);
# endif
`Array2D.c`
Array2D.c
# include "Array2D.h"
# include "StringList.h"

void ReadOptions_init(ReadOptions options){
	options->rows = AUTO;
	options->columns = AUTO;
	options->rowOffset = 0;
	options->columnOffset = 0;
	options->lineSeparators = NULL;
	options->lineSeparatorsCount = 0;
	options->fieldSeparators = NULL;
	options->fieldSeparatorsCount = 0;
	options->repeatedSeparators = TRUE;
	options->ignoreEmptyLines = FALSE;
}
void ReadOptions_finish(ReadOptions options){
	free(options->lineSeparators);
	free(options->fieldSeparators);
}

void ReadOptions_setLineSeparators(ReadOptions options, int lineSeparatorsCount, ...){
	int i;
	va_list list;
	
	options->lineSeparatorsCount = lineSeparatorsCount;
	options->lineSeparators = malloc(lineSeparatorsCount*sizeof(char*));
	va_start(list,lineSeparatorsCount);
	for(i=0;i<lineSeparatorsCount;i++){
		options->lineSeparators[i] = va_arg(list,char*);
	}
	va_end(list);
}

void ReadOptions_setFieldSeparators(ReadOptions options, int fieldSeparatorsCount, ...){
	int i;
	va_list list;
	
	options->fieldSeparatorsCount = fieldSeparatorsCount;
	options->fieldSeparators = malloc(fieldSeparatorsCount*sizeof(char*));
	va_start(list,fieldSeparatorsCount);
	for(i=0;i<fieldSeparatorsCount;i++){
		options->fieldSeparators[i] = va_arg(list,char*);
	}
	va_end(list);
}

void ReadOptions_print(ReadOptions options){
	int i;
	char *p;
	printf("rows : ");
	if(options->rows < 0){printf("Automatic\n");}
	else{printf("%d\n",options->rows);}
	printf("columns : ");
	if(options->columns < 0){printf("Automatic\n");}
	else{printf("%d\n",options->columns);}
	
	printf("row offset : %d\n",options->rowOffset);
	printf("column offset : %d\n",options->columnOffset);
	printf("line separators : ");
	printf("{");
	for(i=0;i<options->lineSeparatorsCount;i++){
		if(i>0){printf(",");}
		for(p=options->lineSeparators[i];*p;p++){
			switch(*p){
			  case '\r': printf("\\r"); break;
			  case '\n': printf("\\n"); break;
			  case '\t': printf("\\t"); break;
			  default: putchar(*p);
			}
		}
	}
	printf("}\n");
	printf("field separators : ");
	printf("{");
	for(i=0;i<options->fieldSeparatorsCount;i++){
		if(i>0){printf(",");}
		for(p=options->fieldSeparators[i];*p;p++){
			switch(*p){
			  case '\r': printf("\\r"); break;
			  case '\n': printf("\\n"); break;
			  case '\t': printf("\\t"); break;
			  default: putchar(*p);
			}
		}
	}
	printf("}\n");
	printf("repeatedSeparators : ");
	if(options->repeatedSeparators == TRUE){
		printf("True\n");
	}else{
		printf("False\n");
	}
	printf("ignoreEmptyLines : ");
	if(options->ignoreEmptyLines == TRUE){
		printf("True\n");
	}else{
		printf("False\n");
	}
}

Array2D Array2D_read(char *string, ReadOptions options){
	StringList list,s,*listlist;
	int i,j,rows,columns,rofs,cofs,c;
	Array2D array=NULL;
	
	list = StringList_splitString(string,options->lineSeparators,options->lineSeparatorsCount,options->ignoreEmptyLines);
	rows = StringList_length(list);
	
	if(options->rowOffset < 0){
		rofs = rows + options->rowOffset;
	}else{
		rofs = options->rowOffset;
	}
	
	if(options->rows < 0){
		if(rows < rofs){
			printf("Array2D_read : row offset %d exceeds the row count %d\n",rofs,rows);
			goto end;
		}
		rows = rows - rofs;
	}else{
		if(rows < options->rows + rofs){
			printf("Array2D_read : rows %d + row offset %d exceeds input data rows %d\n",
				   options->rows,rofs,rows);
		}
		rows = options->rows;
	}

	listlist = malloc(rows*sizeof(StringList));
	for(i=0,columns=0,s=StringList_skip(list,rofs);i<rows && s;i++,s=s->next){
		listlist[i] = StringList_splitString(s->string,options->fieldSeparators,options->fieldSeparatorsCount,options->repeatedSeparators);
		c = StringList_length(listlist[i]);
		if(columns < c){columns=c;}
	}
	
	if(options->columnOffset < 0){
		cofs = columns + options->columnOffset;
	}else{
		cofs = options->columnOffset;
	}
	
	if(options->columns < 0){
		if(columns < cofs){
			printf("Array2D_read : column offset %d exceeds the input data columns%d\n",cofs,columns);
			goto end;
		}
		columns = columns - cofs;
	}else{
		if(columns < options->columns + cofs){
			printf("Array2D_read : columns %d + column offset %d exceeds input data columns %d\n",
				   options->columns,cofs,columns);
		}
		columns = options->columns;
	}
		
	array = Array2D_create(rows,columns);
	
	for(i=0;i<rows;i++){
		for(j=0,s=StringList_skip(listlist[i],cofs);j<columns && s;j++,s=s->next){
			array->data[i][j] = atof(s->string);
		}
	}
  end:
	for(i=0;i<rows;i++){StringList_deleteRoot(listlist[i]);}
	free(listlist);
	StringList_deleteRoot(list);
	
	return array;
}

void Array2D_fprint(Array2D array, FILE *fp, char *sep){
	int i,j;
	for(i=0;i<array->rows;i++){
		for(j=0;j<array->columns;j++){
			fprintf(fp,"%g%s",array->data[i][j],sep);
		}
		fprintf(fp,"\n");
	}
}

void Array2D_print(Array2D array, char *file, char *sep){
	FILE *fp;
	
	fp = fopen(file,"w");
	if(!fp){
		perror("Array2D_print : ");
		return;
	}
	Array2D_fprint(array,fp,sep);
	fclose(fp);
}

Array2D Array2D_create(int rows, int columns){
	Array2D array = malloc(sizeof(Array2D_Sub));
	Array2D_init(array,rows,columns);
	return array;
}

void Array2D_delete(Array2D array){
	Array2D_finish(array);
	free(array);
}

StringList.h
# ifndef STRINGLIST_H
# define STRINGLIST_H
# include <stdio.h>
# include <stdlib.h>
# include <string.h>

typedef struct st_stringlist *StringList;
typedef struct st_stringlist{
	char *string;
	StringList next;
}StringList_Sub;

StringList StringList_print(StringList list);
StringList StringList_create(char *string);
StringList StringList_append(StringList list,char *string);
StringList StringList_last(StringList list);
StringList StringList_skip(StringList list, int k);
int StringList_length(StringList list);
char **StringList_toArray(StringList list);

void StringList_delete(StringList list);
void StringList_deleteRoot(StringList list);
StringList StringList_splitString(char *string, char **separators, int separatorsCount, int repeatedSeparators);
# endif
`StringList.c`
StringList.c
StringList StringList_create(char *string){
	StringList list;
	list = malloc(sizeof(StringList_Sub));
	list->string = string;
	list->next = NULL;
	return list;
}

void StringList_delete(StringList list){free(list);}
void StringList_deleteRoot(StringList list){
	if(list){StringList_deleteRoot(list->next);};
	StringList_delete(list);
}

StringList StringList_last(StringList list){
	for(;list->next;list=list->next){}
	return list;
}

StringList StringList_append(StringList list,char *string){
	if(list){
		StringList_last(list)->next = StringList_create(string);
		return list;
	}else{
		return StringList_create(string);
	}
}

StringList StringList_skip(StringList list, int k){
	int i;
	for(i=0;i<k && list;list=list->next,i++){}
	return list;
}

StringList StringList_print(StringList list){
	if(list){
		for(;list;list=list->next){
			printf("%s\n",list->string);
		}
	}
}

int StringList_length(StringList list){
	int count=0;
	for(;list;list=list->next){count++;}
	return count;
}

char **StringList_toArray(StringList list){
	int i,len;
	char **array;
	len = StringList_length(list);
	array = malloc(len*sizeof(char*));
	for(i=0;i<len;i++,list++){
		array[i] = list->string;
	}
}

StringList StringList_splitString(char *string, char **separators, int separatorsCount,int repeatedSeparators){
	int i,imin,len;
	char *p,*p2,*last,*pmin;
	StringList list=NULL;
	
	last = strchr(string,'\0');
	for(p=string;p<last;p=p2){
		for(i=0,pmin=last,imin=-1;i<separatorsCount;i++){
			p2=strstr(p,separators[i]);
			if(p2){
				if(p2 < pmin){
					imin = i;
					pmin = p2;
				}
			}
		}
		if(imin<0){
			p2 = last;
		}else{
			len = strlen(separators[imin]);
			for(i=0;i<len;i++){pmin[i] = '\0';}
			p2 = &pmin[i];
		}
		if(*p || !repeatedSeparators){list=StringList_append(list,p);}
	}
	return list;
}
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?