マイホーム・マイチルドケア

マイホームと育児と日常

C sample

//テキストファイルの文書を置換するコード
#include <stdio.h> //FILE構造体, fopen, fclose, fgetc, fgets, fseekで使用
#include <stdlib.h> //malloc, freeで使用
#include <string.h>

int fgsds(char **buf, const char *fname, int lines, int *len);
int fgl(const char *fname);
int fglen(int *len, const char *fname);
int fconvrep(const char *fnamer, const char *fnamew, const char *repbef, const char *repaft);

int rep(char *buf, const char *str, const char *repbef, const char *repaft);
int srchn(const char *str, const char *phr);

//macではmallocとstrstrのキャストは不要です(一応残しています)
int main(void)
{
	int i = 0;
	
	const char *fnamer[2] = {"in_file01.txt","in_file02.txt"};
	const char *fnamew[2] = {"file01.txt","file02.txt"};
	const char *repbef = "test"; //置換する語句(文字列)を指定
	const char *repaft = "test"; //置換後の語句(文字列)を指定	
	
	for(i = 0; i < 2; i++)
	{
		fconvrep(fnamer[i], fnamew[i], repbef, repaft);		
	}
	
	return 0;
}

//ファイル変換関数(文字列置換)
int fconvrep(const char *fnamer, const char *fnamew, const char *repbef, const char *repaft)
{
	int lines = fgl(fnamer); //fgl関数を用いて、ファイルの行数を取得
	int *len = (int *)malloc(lines * sizeof(int)); //int型の配列lenの配列数(行数)を設定
	fglen(len, fnamer); //fglen関数を用いて、配列lenに行ごとのバイト数を入れる
	char **buf = (char **)malloc(lines * sizeof(char *)); //格納配列[buf]に行数を確保
	for (int i = 0; i < lines; i++) {
		buf[i] = (char *)malloc((len[i] + 1) * sizeof(char)); //各行に文字列を格納するメモリを確保
	}
	fgsds(buf, fnamer, lines, len); //fgsds関数を用いて、二次元配列bufにファイルの文字列データを格納
	
	//データの変換
	int *lenaft = (int *)malloc(lines * sizeof(int));
	char **bufaft = (char **)malloc(lines * sizeof(char *)); //[bufaft]に行数を入れるメモリを確保
	for (int i = 0; i < lines; i++) {
		lenaft[i] = strlen(buf[i]) + (strlen(repaft) - strlen(repbef)) * srchn(buf[i], repbef);
		bufaft[i] = (char *)malloc((lenaft[i] + 1) * sizeof(char));
		rep(bufaft[i], buf[i], repbef, repaft);
		//printf("計算値 = %d, 実際値 = %d\n", lenaft[i], (int)strlen(bufaft[i])); //確認用
	}
	
	//データを新ファイルに格納
	FILE *fpw = fopen(fnamew, "wb");
	if (fpw == NULL) {
		printf("file open error! 新ファイル%s\n",fnamew);
		return -1;
	}
	for (int i = 0; i < lines; i++) {
		fputs(bufaft[i], fpw);
	}
	
	//メモリの解放
	fclose(fpw);
	for (int i = 0; i < lines; i++) {
		free(bufaft[i]); //各行のメモリを解放
	}
	free(bufaft);
	free(lenaft);
	for (int i = 0; i < lines; i++) {
		free(buf[i]); //各行のメモリを解放
	}
	free(buf);
	free(len);
	
	return 0;
}

//fgsds関数(二次元配列を使ってファイル内の文字列データを行ごとに格納する関数)
int fgsds(char **buf, const char *fname, int lines, int *len)
{
	FILE *fp = fopen(fname, "rb");
	if (fp == NULL) {
		printf("file open error!元ファイル\n");
		return -1;
	}
	for (int i = 0; i < lines && fgets(buf[i], len[i] + 1, fp) != NULL; i++) {}
	fclose(fp);
	return 0;
}

//fgl関数(ファイルの行数を取得する関数)
int fgl(const char *fname)
{
	FILE *fp = fopen(fname, "rb");
	int c;
	int lines = 0; //行をカウントする変数
	if (fp == NULL) {
		printf("file open error! 行カウント用 %s\n",fname);
		return -1;
	}
	
	while (1) {
		c = fgetc(fp);
		if (c == '\n') { //改行があるたびに行をカウント(なお、fgetsの場合'\n'を改行として認識する)
			lines++;
		} else if (c == EOF) { //最終行に改行がされていない場合も1行として拾うための処置
			lines++;
			break;
		}
	}
	
	fclose(fp);
	return lines;
}

//fglen関数(ポインタ[len]にファイルの行ごとのバイト長を格納する)
int fglen(int *len, const char *fname)
{
	FILE *fp = fopen(fname, "rb");
	int c;
	int i = 0;
	int byt = 0; //バイト数のカウント用
	int bytc = 0; //変数bytの一時コピー用
	if (fp == NULL) {
		printf("file open error!\n");
		return -1;
	}
	
	while (1) {
		c = fgetc(fp);
		byt++;
		if (c == '\n') {
			len[i] = byt - bytc;
			i++;
			bytc = byt; //bytの数値をbytcにコピー
		} else if (c == EOF) {
			if ((byt - bytc) <= 1) { //最後が改行で終わっている場合
				len[i] = 0;
			} else {
				len[i] = byt - bytc; //最後が改行で終わっていない場合
			}
			break;
		}
	}
	
	fclose(fp);
	return 0;
}

//rep関数(文字列置換関数)※マルチバイト文字に対応
int rep(char *buf, const char *str, const char *repbef, const char *repaft)
{
	char *pos; //strstr関数で使用するポインタ
	char *poss = (char *)str; //検索開始のポインタの位置(possとは[pos + start]の意)
	int beflen = strlen(repbef); //検索語句の長さ
	strcpy(buf, "\0"); //strcpyは第2引数のNULL終端を含めコピーする(バッファオーバーランには注意)
	
	while(1) {
		pos = (char *)strstr(poss, repbef);
		if (pos == NULL) {
			strcat(buf, poss); //strcatもNULL終端する(バッファオーバーランには注意)
			break;
		} else {
			strncat(buf, poss, pos - poss); //strncatもNULL終端する(バッファオーバーランには注意)
			strcat(buf, repaft); //strcatもNULL終端する(バッファオーバーランには注意)
			poss = pos + beflen; //poss += len + beflen;
		}
	}
	return 0;
}

//srchn関数(対象文字列に含まれる検索語句数をカウント)※マルチバイト文字対応
int srchn(const char *str, const char *phr)
{
	char *pos;
	char *poss = (char *)str; //検索開始のポインタの位置(possとは[pos + start]の意)
	int num = 0;
	int phrlen = strlen(phr);
	
	while(1) {
		pos = (char *)strstr(poss, phr);
		if (pos == NULL) {
			break;
		} else {
			num++;
			poss = pos + phrlen;
		}
	}
	return num;
}