13.基本アルゴリズム

13-2. 文字列の置換

 テキストファイルと検索文字列そして置換後の文字列を指定し、標準出力に表示します。
 それでは早速、プログラミング作成を行ってみましょう。
まず、検索用の関数のアルゴリズムを変更して置換用の関数を作成します。

<関数仕様>
関数名:char *permute_str(const char *a, const char *b, const char *c)
引数 :a 検索の対象となる文字列へのポインタ
    b 検索する文字列へのポインタ
c 置換する文字列へのポインタ
戻り値:置換後の文字列の先頭アドレス

◇置換用の関数

char *permute_str(const char *a, const char *b, const char *c)
{
    int  i=0, max_a, max_b;
    char result[256];
    result[0] = '\0'; // 念のため最初の文字をNULLにする

    // 文字列の最大文字数(半角)を調べる
    max_a = strlen(a);
    max_b = strlen(b);

    for( i = 0; i <= max_a; i++ ){
        if( 0==strncmp(&a[i], b, max_b) ){
            strcat(result,c);
            i += max_b-1;
        }
        else{
            strncat(result,&a[i],1);
        }
    }
    return result;
}

 先ほど作りました置換関数を利用してファイル全文置換を行うプログラムを以下に紹介します。

◇サンプルプログラム

#include<stdio.h>
#include<string.h>
char *permute_str(const char *a, const char *b, const char *c);

void main()
{
        FILE *fp_i,*fp_o;
        char *res;
        char a[100],fname[256],fname2[256],sstr[100],cstr[100];
        printf("検索されるファイル名 : ");
        scanf("%s",fname);
        printf("出力先のファイル名 : ");
        scanf("%s",fname2);
        printf("置換前の文字列 : ");
        scanf("%s",sstr);
        printf("置換後の文字列 : ");
        scanf("%s",cstr);

        if( (fp_i=fopen(fname,"r"))==NULL){
                printf("ファイル %s が見つかりません\n",fname);return;
        }
        else{
                fp_o=fopen(fname2,"w");
        }
        while(fgets(a,100,fp_i)!=NULL){
                res = permute_str(a, sstr, cstr);
        fprintf(fp_o,"%s",res);
        }
        fclose(fp_i);
        fclose(fp_o);
        return;
}

char *permute_str(const char *a, const char *b, const char *c)
{
    int  i=0, max_a, max_b;
    char result[256];
    result[0] = '\0'; // 念のため最初の文字をNULLにする

    // 文字列の最大文字数(半角)を調べる
    max_a = strlen(a);
    max_b = strlen(b);

    for( i = 0; i <= max_a; i++ ){
        if( 0==strncmp(&a[i], b, max_b) ){
            strcat(result,c);
            i += max_b-1;
        }
        else{
            strncat(result,&a[i],1);
        }
    }
    return result;
}

◇応用例

 文字列置換の応用範囲は広いのですが、今回作成した置換関数はテキストエディタの機能としてはもちろん
(VC++ならわざわざ自作するまでも無い気がしますが)
 CGIとHTMLデザインを分離して開発する場合においては、動的HPの開発アルゴリズムに加えればかなり作業の効率化が行えます。
 私の場合は、ページデザインの変更があっても更新する必要の無い動的HP生成CGIやサイトの汎用システムとして開発しています。
 (もっともPerl言語で開発してたりしますが・・・)

 こういう不便から生まれたアイディアやアルゴリズムってあまり教えたくは無いのですね。(未だにCGI中にHTML書く人が沢山いそうなので)

◇タブ→スペース変換

 前回の文字列を置換を利用して、タブをスペースに変換するプログラムを作ってみます。

置換関数は前に作ったものを利用します。プログラム的には少しの変更で済みますが、今回は汎用性を考えて変更せず以前の仕様のまま利用します。

◇サンプルプログラム

#include<stdio.h>
#include<string.h>
char *permute_str(const char *a, const char *b, const char *c);

void main()
{
        FILE *fp_i,*fp_o;
int i,space;
        char *res;
        char a[100],fname[256],fname2[256],sstr[]="\t",cstr[100];
cstr[0]='\0';
        printf("入力ファイル名 : ");
        scanf("%s",fname);
        printf("出力ファイル名 : ");
        scanf("%s",fname2);
        printf("TAB1つ当たりのスペース数 : ");
        scanf("%d",&space);

for (i=1;i<=space;i++){
strcat(cstr," ");
}

        if( (fp_i=fopen(fname,"r"))==NULL){
                printf("ファイル %s が見つかりません\n",fname);return;
        }
        else{
                fp_o=fopen(fname2,"w");
        }
        while(fgets(a,100,fp_i)!=NULL){
                res = permute_str(a, sstr, cstr);
        fprintf(fp_o,"%s",res);
        }
        fclose(fp_i);
        fclose(fp_o);
        return;
}

char *permute_str(const char *a, const char *b, const char *c)
{
    int  i=0, max_a, max_b;
    char result[256];
    result[0] = '\0'; // 念のため最初の文字をNULLにする

    // 文字列の最大文字数(半角)を調べる
    max_a = strlen(a);
    max_b = strlen(b);

    for( i = 0; i <= max_a; i++ ){
        if( 0==strncmp(&a[i], b, max_b) ){
            strcat(result,c);
            i += max_b-1;
        }
        else{
            strncat(result,&a[i],1);
        }
    }
    return result;
}

◇利用例

 これはまさしくテキストエディタ用としてよく使われる機能です。気の利いたフリーのエディターでは標準でついていたりしますね。
 また、上記のようなコマンドライン型であれはネット上のテキスト整形に使えるのでは、と思います。(どちらかというとスペース→タブの方かな?)

 次回は、スペース→TAB変換を予定しています。
自分としてはこちらの方が便利な場面が多く、お役に立てるかと思います。

◇スペース→タブ変換

 今回は、スペース→タブ変換。。。
えっ?前回と同じですって???
いえいえ、別に手抜きではありません。前回の逆変換です(爆)
(・・・それが手抜きのようにみえるんだって!)

・・・それはさておき、
 個人的にも、こちらの方がツールに無い分重宝するときがあります。
このメールマガジンでもそうですが、見た目が人によって相違ないようタブは使わずスペースを使っています。
 実は、図を描くときなんか全角と半角を混合するのを避けたりしてレイアウトが崩れるのを避けようと努力したりしてました。

・・・で、スペース→タブ変換ですが、メールマガジンやホームページ等で掲載されているプログラムソースをコピー&ペーストして使いたい!
というときにインデントされているスペースをタブに変換するのです。
もちろん、プログラムのインデントにはタブのほうが断然便利が良いのでこういう機能こそ汎用テキストエディタにあるととてもうれしいのです。
(そういう意味でVC++のエディタは優秀かも、VBのエディタは中途半端)

プログラムも殆ど前回と変わらないのですが、どこが変わったかご注目(笑)

◇サンプルプログラム

#include<stdio.h>
#include<string.h>
char *permute_str(const char *a, const char *b, const char *c);

void main()
{
        FILE *fp_i,*fp_o;
int i,space;
        char *res;
        char a[100],fname[256],fname2[256],sstr[]="\t",cstr[100];
cstr[0]='\0';
        printf("入力ファイル名 : ");
        scanf("%s",fname);
        printf("出力ファイル名 : ");
        scanf("%s",fname2);
        printf("TAB1つ当たりのスペース数 : ");
        scanf("%d",&space);

for (i=1;i<=space;i++){
strcat(cstr," ");
}

        if( (fp_i=fopen(fname,"r"))==NULL){
                printf("ファイル %s が見つかりません\n",fname);return;
        }
        else{
                fp_o=fopen(fname2,"w");
        }
        while(fgets(a,100,fp_i)!=NULL){
                res = permute_str(a, cstr, sstr);
        fprintf(fp_o,"%s",res);
        }
        fclose(fp_i);
        fclose(fp_o);
        return;
}

char *permute_str(const char *a, const char *b, const char *c)
{
    int  i=0, max_a, max_b;
    char result[256];
    result[0] = '\0'; // 念のため最初の文字をNULLにする

    // 文字列の最大文字数(半角)を調べる
    max_a = strlen(a);
    max_b = strlen(b);

    for( i = 0; i <= max_a; i++ ){
        if( 0==strncmp(&a[i], b, max_b) ){
            strcat(result,c);
            i += max_b-1;
        }
        else{
            strncat(result,&a[i],1);
        }
    }
    return result;
}

 前回のプログラムで理解してる方はすでにお分かりだと思います。
はっきりいって間違い探し並みの変更の少なさです。
(難易度:バグ取りレベル)