//テキストファイルの文書を置換するコード
#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;
}