■ テーブルによる文字列置換
/*
* replace.c : テーブルによる文字列置換
*
* Copyright (c) 2002 AOK.
*
* 2002/07/24 - 初版
*
* 使い方: REPLACE ファイル名
*
* 【置換テーブルの記述の仕方】
*
* 検索文字列 タブ 置換文字列 改行
*
* 各文字列では、 0x0a(改行)は \n
* 0x09(タブ)は \t
* 0x5c(\) は \\
* 0x0d は \r
* と記述すること。
*
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#include "misc.h"
#define BUFLEN 32767
#define DATA_FILENAME "han2zen.dic"
void error_msg(int no);
typedef struct tagTABLE {
char *str_i; /* 検索文字列 */
char *str_o; /* 置換文字列 */
struct tagTABLE *next; /* 次テーブルへのポインタ */
} TABLE;
TABLE start = { NULL, NULL, NULL }; /* 置換テーブルの先頭 */
char data[FILENAME_MAX]; /* 置換テーブルファイル名 */
char infile[FILENAME_MAX]; /* 入力ファイル名 */
char outfile[FILENAME_MAX]; /* 出力ファイル名 */
/*
* 文字列の置換
*
* 【引数】
* t ---- 検索対象の文字列
* f ---- 検索文字列
* r ---- 置換文字列
*
* 【戻り値】
* 置換結果文字列を格納したバッファへのアドレス。
* 内部でメモリを確保しているため、使用後は、戻り値を
* 引数として free すること。
*
*/
char *replace(const char *t, const char *f, const char *r)
{
char *p1, *p2, *rt, *sv;
int x1, x2, c = 0;
if (!t || !f || !r) return NULL;
x1 = strlen(f);
x2 = strlen(r);
/* 先に一致する数を求めておく */
p1 = (char *)t;
while ((p2 = strstr(p1, f)) != NULL) {
if (!is_kanji2(t, p2-t)) {
p1 = p2 + x1;
c++;
}
p1++;
}
/* 置換後の文字列を格納する領域の確保 */
sv = rt = malloc(strlen(t) + (x2 - x1) * c + 1);
if (!sv) return NULL;
/* 置換処理の実行 */
p1 = (char *)t;
while (*p1 != '\0') {
if (strncmp(p1, f, x1) == 0) {
if (!is_kanji2(t, p1-t)) {
strcpy(rt, r);
p1 += x1;
rt += x2;
continue;
}
}
*rt++ = *p1++;
}
*rt = '\0';
return sv;
}
/* 置換テーブルに値をセット */
void set_table(char *str, int pos)
{
char *p1, *p2, *sv = str;
static TABLE *ptbl = NULL, *stbl = &start;
p2 = p1 = malloc(strlen(str)+1);
while (*sv) {
if (*sv == '\\' && !is_kanji2(str, sv-str)) {
sv++;
if (*sv == 't') *p1++ = '\t';
else if (*sv == 'n') *p1++ = '\n';
else if (*sv == 'r') *p1++ = '\r';
else if (*sv == '\\') *p1++ = '\\';
else {
error_msg(4);
*p1++ = '\\'; /* 処理は続行 */
continue;
}
sv++;
continue;
}
*p1++ = *sv++;
}
*p1 = '\0';
if (!pos) {
ptbl = (TABLE *)calloc(sizeof(TABLE), 1);
if (ptbl) ptbl->str_i = p2;
} else {
if (ptbl) ptbl->str_o = p2;
stbl->next = ptbl;
stbl = ptbl;
}
}
/* 置換テーブルの読みこみ */
int read_table(void)
{
FILE *fp;
char s[BUFLEN], *p;
if ((fp = fopen(data, "rt")) == NULL) return 0;
while (fgets(s, BUFLEN, fp)) {
p = strtok(s, "\t\n");
if (p) set_table(p, 0);
p = strtok(NULL, "\t\n");
if (p) set_table(p, 1);
}
fclose(fp);
return 1;
}
/* 置換テーブルデータの解放 */
void free_table(void)
{
TABLE *ptbl, *stbl = start.next;
while (stbl) {
ptbl = stbl;
if (ptbl->str_i) free(ptbl->str_i);
if (ptbl->str_o) free(ptbl->str_o);
stbl = ptbl->next;
free(ptbl);
}
}
/* テーブル置換の実行 */
char *table_convert(char *s)
{
TABLE *stbl = start.next;
char *d;
while (stbl) {
if (!s) return NULL;
d = replace(s, stbl->str_i, stbl->str_o);
free(s);
s = d;
stbl = stbl->next;
}
return d;
}
/* エラーメッセージの表示 */
void error_msg(int no)
{
static const char *msg[] = {
"入力ファイルを指定して下さい。\n\n使い方: REPLACE ファイル名\n",
"%s をオープン出来ません。\n",
"%s に不正な文字があります。\n"
};
printf("error: ");
switch (no) {
case 1: printf(msg[1], infile); break;
case 2: printf(msg[1], outfile); break;
case 3: printf(msg[1], data); break;
case 4: printf(msg[2], data); break;
default: printf(msg[0]); break;
}
}
/* メインルーチン */
int main(int argc, char *argv[])
{
FILE *fi, *fo;
long size;
char *src;
if (argc < 2) {
error_msg(0);
return 1;
}
strcpy(infile, argv[1]);
change_ext(outfile, infile, "out");
if ((fi = fopen(infile, "rt")) == NULL) {
error_msg(1);
return 1;
}
if ((fo = fopen(outfile, "wt")) == NULL) {
error_msg(2);
fclose(fi);
return 1;
}
extract_path(data, argv[0]);
strcat(data, DATA_FILENAME);
if (!read_table()) {
error_msg(3);
return 1;
}
size = filelength(fileno(fi));
src = calloc(size*sizeof(char)+1, 1);
if (fread(src, sizeof(char), size, fi)) {
*(src+size) = '\0';
src = table_convert(src);
if (src) fputs(src, fo);
}
if (src) free(src);
fclose(fi);
fclose(fo);
free_table();
printf("置換終了 [%s]\n", outfile);
return 0;
}