タブ区切り(TSV)形式、カンマ区切り(CSV)形式の数値ファイルを読み取るプログラムを作ります。いろいろと汎用性が高いものになっています。
二次元配列のクラス作成
二次元配列とその行数、列数の情報をまとめて扱う二次元配列のクラスを作成します。命名法を工夫するだけでオブジェクト指向ができるC言語のオブジェクト指向的な記法を使います。
構造体を定義して、そのポインタをtypedefします。構造体を操作する関数(メソッド)は必ずtypedefした構造体のポインタを第一引数として受け取ります。コンストラクタはクラス名_create クラス名_deleteとします。
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`
# 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);
}
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言語 可変長引数関数について 【初心者向け】)
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 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のテストコード
# 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列のデータを読み取る。
# 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クラス
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`
# 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のテストコード
# 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 StringList_splitString(char *string, char **separators, int separatorsCount, int repeatedSeparators);
stringはもとの文字列、separatorsは区切り文字のリスト、separatorsCountは区切り文字の数、repeatedSeparatorsは連続する区切り文字を無視するかどうかのフラグです。
仕様としてこの関数は、入力の文字列に対して区切り文字がある位置を\0で入れ替えるという破壊的処理を行います。なので入力の文字列は必ずmallocなどでメモリ上に確保した領域上のものである必要があります。
分割された文字列のメモリをいちいち確保するのは非効率なので、このような仕様にしました。
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 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;
}
ファイルから二次元配列を読み取るプログラム
これまで作ったクラスを使って目的のプログラムを完成させます。
ファイルから配列を読み取って表示するだけのわりに、汎用性を高めてあるのでわりとボリューム感があります。
完成です。ありがとうございました。
# 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;
}
# 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`
# 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;
}
# 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`
# 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);
}
# 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 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;
}