C言語でファイルから文字列を検索・削除したい
ゲスト
ゲスト
ATOMRSS
  • コード求むID: 297
  • 登録日時:  2008/07/09 23:13
  • 最終更新日時: 2008/07/28 22:01
  • アクセス数: 3546
  • タグ:  c言語 ファイル 文字列 削除
  • codeなにがしブックマークに追加する 0 users
  • このページを del.icio.us に追加
  • このページをはてなブックマークに追加

C言語を趣味で勉強しているものです。
半角英数のテキストファイルhogeから文字列を検索して削除したいのですが、どのように記述してよいか分かりません。参考になるサイト等ありましたら教えていただけないでしょうか?

例えば
テキストファイル  hoge
konnnitiha
kyouhaiitennkideshita
ashitamoiitennki

からiitennkiを検索・削除して

テキストファイル hoge
konnnitiha
kyouhadeshita
ashitamo

と変更したいと思っております。


コメント

いきなりコード乗せちゃうのもなんですが調べがてらつい・・・
参考にしたサイトはこちらです。
http://www9.plala.or.jp/sgwr-t/lib/lib.html

#include <stdio.h>
#include <string.h>

int main(){
    char *strings[3] {"konnnitiha",
        "kyouhaiitennkideshita",
        "ashitamoiitennki",
    };
    char *del_string "iitennki";

    int i;
    for(i=0;i<sizeof strings sizeof strings[0];i++){
        char *s strstr(strings[i], del_string);

        if(s == NULL){
            puts(strings[i]);
            continue;
        }

        char *c strings[i];
        while(c != s){
            putchar(*c++);
        }
        += strlen(del_string);
        printf("%s\n", s);    
    }

    return 0;
}

かなりムリヤリ>< 
もっときれいなのだれかお願い。

GJGJGJ

  • ゲスト
  • 2:ゲスト
  • 2008/07/10 04:26

複数回見つかる可能性もある場合は、考えなくていいのでしょうか?

regex.c を見るといいかも。

GJ

  • ゲスト
  • 3:ゲスト ((質問者))
  • 2008/07/10 19:13

>1:mikeda様
回答ありがとうございます。
具体的なコードを示していただき、初心者としては大変ありがたいです。
いろいろいじってみて目的の処理ができるように頑張りたいと思います!
参考サイトも教えていただきありがとうございました。

>2:ゲスト様
回答ありがとうございます。
質問が不十分でした、複数回見つかる可能性も考えなければなりません・・・
検索してみたところ、以下のようなサイトが参考になりそうです。
http://www.sip.eee.yamaguchi-u.ac.jp/kou/regex.html
http://sometime.minidns.net/~ccgi/posix_reglib.html
自分にとってはかなり難しいですが、なんとか頑張って理解しようと思います。

GJGJ

GJ

2
あw 複数回、考慮するの完全に忘れてましたwww
そのへんふまえてループなり再帰なりで関数外出しすればけっこうすっきり書けそうですね。

Cの正規表現って使ったことないです。思ったほどはめんどくさくなさそう。また試してみます!

3
入出力はファイル、ってのも無視だし、変数名とか関数の使い方とか、テキトーで申し訳ないです。
それにポインタ演算とかちょっと理解しずらいかもです。もう少し簡単に書ければいいんですが。

紹介サイト、参考になりました。困ったことがあればなんでも。がんばってください。

GJGJGJ

GJ

ポインタ使わずsubstrとindexofでやれば、と思ったけどC言語にはなかったんだっけ・・・

GJ

  • ゲスト
  • 6:ゲスト
  • 2008/07/11 04:39

5>substrとindexofでやれば、と思ったけどC言語にはなかったんだっけ・・・
C言語にはないですね。
こういう処理をするなら、特にC言語にこだわりがないなら、
Perl とかそういう言語を用いた方がいいと思う。
(C++でもいいけど)

GJ

  • ゲスト
  • 7:ゲスト (質問者)
  • 2008/07/11 20:43

すみません、一応いろいろやってはみたのですが、入門書を終えただけの私にはどうしても解決できませんでした。

テキストファイルhoge.txtは以下のようになっています

kyouhaiitennki
ashitahaiitennkiiitennki
sonouthihareruyo
iitennki
sorenisshitemoiitennki
KKKKKKKKKKKK
iitennki

これを、最終的には

kyouha
ashitaha
sonouthihareruyo
sorenisshitemo
KKKKKKKKKKKK

としたいと思っています。

[code]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(){
    
    FILE    *fp;
    char str[256];                                    // ファイルの1行分
    char *temp;
    int i=0;
    
    char    *fname        "hoge.txt";
    char *del_string "iitennki";
    
    if((fp fopen(fname,"r+")) == NULL){            // 開いて、結果のチェック
    
        printf("file open error!!\n");
        exit(EXIT_FAILURE);                            // 開けないなら異常終了
    
    }else{
        

        while(fgets(str,256,fp) != NULL){
            
            char *s strstr(str, del_string);
            
            /* 見つからなかったら一行出力して次の行へ */
            if(s == NULL){
                fputs(str,fp);
                continue;
            }
            
            /* 一文字ずつファイルに書き込む */
            while(str != s){
                fputc(str,fp);
            }
            
            /* 消す文字の分だけsを進める */
            += strlen(del_string);
            fprintf(fp,"%s\n",s);
        }
    }
    
    fclose(fp);
            
    return(0);
}
[/code]

本当に幼稚なレベルで申し訳ないのですが、何かアドバイスをいただけないでしょうかm(_ _)m

GJGJGJGJGJGJGJGJGJGJGJGJGJGJGJGJ

GJGJGJGJGJGJGJGJGJ

  • ゲスト
  • 8:ゲスト (質問者)
  • 2008/07/11 20:51

すみません、プレビューせずに書き込みをしたので少し変です。

GJ

プログラムは一気に書かずにちょっとずつ動作を確認しながら書きましょう。そっちのほうが絶対早いですよ。


まず読込みファイルと書き込みファイルは別にしましょう。FILEにはファイル中での現在の位置等含まれています。読み書き同時は厳しいです。

あと文字列からファイルに1文字ずつ書き込む処理では、文字列の中を1つずつ進んでいかなくてはいけません。私のプログラムでputchar(*c++);となっている++の部分です。
それにからめて、(ちょっと難しいので無理に理解しようとしないでください。説明もいい加減です。絶対だれかに怒られる・・・)
char *p "abc";
ではpはcharへのポインタになるのですが
char str[4] "abc";
ではstrは配列になるので1を足す意味が違ってしまいます。
1文字ずつ進めるにはcharのポインタじゃないといけないのでstrではなくchar *p=(char *)str;等で作ったpを使いましょう。

GJGJ

  • mikeda
  • 10:mikeda
  • 2008/07/12 00:05

で、自分で書いておいてなんですが、1文字ずつ進めるより以下の方が簡単かもしれません。

//strに1行読み込み
fgets(str,256,in_fp);
//検索して見つかった先頭位置をsに
char *s strstr(str, del_string);
//sの部分を¥0にする。
*s='\0';
//¥0は文字列の終わりと見なされるのでとりあえずそこまで出力
fprintf(out_fp, "%s", str);
//sを削除文字の文字数ぶん進めて
+= strlen(del_string);
//残りの部分を出力
fputs(s, out_fp);

どっちもどっちでしょうか。

GJGJGJ

  • ゲスト
  • 11:ゲスト (暇人)
  • 2008/07/12 02:43

>prog <hoge.txt >result.txt

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//指定された位置から指定サイズを取り除く
char *strdel(char *s, size_t len){
    size_t i=0;

    while(s[i]=s[i+len])
        i++;
    return (s);
}


int main(){
    FILE *fi,*fo;
    char str[256]; //1行分
    char *temp;
    int del_size;
    
//  const char *fname      "hoge.txt";
    const char *del_string "iitennki";
    
    del_size=strlen(del_string);
    fi=stdin;
    fo=stdout;

    while(fgets(str, 256, fi) != NULL){
        char *s=str;

        while(s=strstr(s, del_string)){
            strdel(s, del_size);
        }
        if(strlen(str)>1){//改行だけになってしまったら削除する(入力ファイルに改行のみのデータは無いと仮定)
            fputs(str, fo);
        }
    }
            
    return 0;
}

GJGJGJGJGJGJGJGJGJ

  • ゲスト
  • 12:ゲスト (質問者)
  • 2008/07/12 20:04

>9:mikeda様
回答ありがとうございます。
ポインタについて、詳しく書いてある本を買ってきて少し勉強しました。これからしっかり理解できるよう努力します。それと、mikeda様のアドバイスを参考に、何とかhoge.txtから指定文字列を取り除くプログラムが出来ました!
と言っても、正直試行錯誤していたら、たまたまうまくいったという感じなのですが・・・
これから複数回を取り除く処理を考えて、すっきりとしたコードになるように頑張ります。
大変親切に回答していただき、本当にありがとうございました!!

>11:ゲスト(暇人)様
回答ありがとうございます。
なるほど、そのように関数を作ればすっきり書けるのですね!
まずは今の方針で、なんとかきれいなソースになるようにしてみようと思います。その後で、ゲスト(暇人)様が書いてくださったものと比べてどこがどう違うのか見てみたいと思います。
とてもいい勉強になりましたm(_ _)m

GJ

  • ゲスト
  • 13:ゲスト
  • 2008/07/13 03:02

11>if(strlen(str)>1){
は、あんまりだ。
もっと条件を絞らないとダメだと思う。

GJ

  • ゲスト
  • 14:ゲスト (暇人)
  • 2008/07/14 03:48

12>まずは今の方針で
一文字ずつ出力する方針だと、
指定した文字を削除(出力をスキップ)したために改行だけになった場合、
改行を出力しない、というのが面倒な気がします。

GJ

  • kumazo
  • 15:kumazo
  • 2008/07/14 22:16

もう終わってますが・・・

バッファ操作の課題ではありませんか?
せっかくC言語を勉強しているのだから、
メモリ上を"歩く"経験も積んでおいたほうがいいですよ。
コンピュータへの理解が深まります。

今のうちに、時間がかかっても、ちゃんとフローチャートや状態遷移図をかいて、
自分のアタマで考えることをお勧めします。

ということでポインタを使ったアタマの体操。

char strremove(char *strbuff, char *ngword) {
    char *read_pos strbuff;  /* read */
    char *write_pos strbuff; /* write */
    char *comp_pos ngword;   /* compare */
    char *anch_pos NULL;     /* anchor */
    
    while *read_pos != '\0' {
        if (anch_pos == NULL) {
            if *read_pos == *comp_pos {
                anch_pos write_pos;
                comp_pos ++;
            }
        }
        else {
            if *comp_pos == '\0' {
                write_pos anch_pos;
                anch_pos NULL:
                comp_pos ngword;
            }
            else if *read_pos != *comp_pos {
                anch_pos NULL:
                comp_pos ngword;
            }
            else {
                comp_pos ++;
            }
        }
        
        *write_pos *read_pos;
        write_pos ++ ;
        read_pos ++;
   }
   write_pos '\0';
   return strbuff;
}

コンパイラに通してないので、動かなかったらごめんなさい。

GJGJGJGJGJ

  • ゲスト
  • 16:ゲスト (暇人)
  • 2008/07/19 07:08

VB系のReplace 関数モドキを作って
書き直してみた。

//delstr.exe <hoge.txt >result.txt
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
int replace(被置換文字列を含む文字列, 検索文字列, 置換文字列, 検索開始位置, 置換回数, 大文字小文字を同一視, 出力領域)
返値は、置き換えた回数
*/
int replace(const char *s, const char *find, const char *rep, size_t pos, int count, int ignore, char *buff){
	size_t i, len_f, len_r;
	int rep_count=0;
	int (*cmp)(const char*, const char*, size_t);
	
	cmp = (ignore) ?  strnicmp : strncmp;
	len_f = strlen(find);
	len_r = strlen(rep);
	
	for(i=0;i<pos;i++)//検索開始位置まで出力
		*buff++ = *s++;

	while(rep_count != count){
		if(cmp(s, find, len_f)){ //一致しない
			*buff++ = *s++;
		} else { //一致した
//			strncpy(buff, rep, len_r);
//			buff += len_r;
			for(i=0;i<len_r;i++)
				*buff++ = rep[i];
			s += len_f;
			rep_count++;
		}
		if(*s=='\0')//文字列終了
			break;
	}
	while(*s){ //文字列が残っている場合出力
		*buff++ = *s++;
	}
	*buff = '\0';

	return rep_count;
}


int main(){
    FILE *fi,*fo;
    char str[256]; //1行分
    char buf[256]; //出力作業用領域

    const char *del_string = "iitennki";
    const char *rep_string = "";

    fi=stdin;
    fo=stdout;

    while(fgets(str, 256, fi) != NULL){
        if(replace(str, del_string, rep_string, 0, -1, 0, buf)){ //一致したものを全部削除する
        	if(*buf!='\n'){ //改行だけになってしまったら削除する
        		fputs(buf, fo);
        	}
    	} else {//置き換えがなかったらそのまま出力
    		fputs(str, fo);
    	}
    }

    return 0;
}

GJGJGJGJGJGJGJ

GJGJGJGJGJ

  • ゲスト
  • 17:ゲスト
  • 2008/07/28 22:01

#include<stdio.h>
#include<string.h>
#define MAX 50
#define NEWFILE "newfile.txt"

void remove_NG(char* str,char* NGword);

int main()
{
    FILE* rp;
    FILE* wp;
    char filename[MAX];
    char NGword[MAX];
    char buff[MAX*3];
    
    printf("ファイル名を入力してください:");
    scanf("%s",filename);
    
    printf("NGワードを入力してください:");
    scanf("%s",NGword);
    
    //ファイルオープン(エラー処理は省く)
    rp fopen(filename,"r");
    wp fopen(NEWFILE,"w");
    
    while (fgets(buff,MAX*3,rp) != NULL) {
        int buff_len strlen(buff);
        
        //NGワードを取り除く
        remove_NG(buff,NGword);
        
        //NGワードを取り除いたものを書き出す
        for (int i=0; i<buff_len; i++)
            if (buff[i] != '\0')
                fputc(buff[i],wp);
    }
    
    fclose(rp);
    fclose(wp);
    
    return 0;
}

void remove_NG(char* str,char* NGword)
{
    char NGlen strlen(NGword);
    char* NGpos strstr(str,NGword);
    
    while (NGpos != NULL) {
        
        for (int i=0; i<NGlen; i++) {
            *NGpos++ '\0';             
               
        NGpos strstr(NGpos,NGword);
    }
}
    
    

GJGJGJGJGJGJGJGJGJGJGJGJ

前へ 1 次へ

コメントする

[block]から[/block]までの範囲はブロック表示されます。
部分的に目立たせたい時や、引用などにお使いください。

[code]から[/code]までの範囲は等幅表示されます。
ソースコードや設定ファイルの記述などにお使いください。

ゲスト投稿者:ゲスト:

関連ソースコード・ノウハウを登録

PDFLib | A library for processing PDF on the fly プレゼン公開・共有サイト handsOut.jp オープンタイプ株式会社 チーム・マイナス6% - みんなで止めよう温暖化

ブックマークコメント