Last Update: Jul.24,2002

C Source Library

「LSI C-86 Ver.3.30c 試食版」、「Borland C++ 5.5」でコンパイル出来ます。

■ テーブルによる文字列置換

/*
 *  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;
}