No.17199![]() |
2バイト文字対応の検索 投稿者---Sciggepy(2004/10/09 11:44:47) |
||
2バイト文字を含む文字列で、(パターン)検索・置換を行いたいのですが、1バイト文字の関数のどの部分を変更すればよいのでしょうか? 以下、1バイト文字での実験に使ったソースです。 #include <stdio.h> #include <stdlib.h> struct prds { const char *fs; unsigned len; } prdata[10]; unsigned nprd; #define prd_set(f,l,n) {prdata[n].fs=(f); prdata[n].len=(l);} void prd_insert(const char *f,unsigned l,unsigned n) { unsigned i; for(i=n;i<9;i++) prdata[i+1]=prdata[i]; prd_set(f,l,n); } int patfind(const char *str,const char *pat) { const char *fs; unsigned long c,i,nd; for(;;) switch(*pat) { case '\0': return *str==*pat; case '\\': if(*(str++)!=*(++pat)) return 0; pat++; break; case '?': if(!(c=strtoul(++pat,(char **)&pat,10))) c=1; for(i=0;i<c;i++,str++) if(*str=='\0') return 0; if(nd<10) prd_set(str-i,i,nd); nprd++; break; case '*': for(fs=str,pat++,nd=nprd,i=0;*str;str++,i++) if(patfind(str,pat)) { prd_insert(fs,i,nd); nprd++; return 1; } if(*str==*pat) { prd_insert(fs,i,nd); nprd++; return 1; } return 0; default: if(*(str++)!=*(pat++)) return 0; } } unsigned patrep(const char *str,const char *pat,const char *opt,char *ret,unsigned cmax) { unsigned i,j,len; for(i=0;i<10;i++) prd_set(NULL,0,i); nprd=0; if(patfind(str,pat)) { for(i=nprd;i<10;i++) prd_set(NULL,0,i); for(i=0,len=0;opt[i];i++) { if(opt[i]=='$') { if(opt[++i]=='$') { if(len>=cmax-1) break; ret[len++]='$'; } else if((opt[i]>='0')||(opt[i]<='9')) { struct prds *pd; pd=&prdata[opt[i]-'0']; for(j=0;j<pd->len;j++) { if(len>=cmax-1) break; ret[len++]=pd->fs[j]; } } } else { if(len>=cmax-1) break; ret[len++]=opt[i]; } } ret[len]='\0'; return len; } return -1; } int main(void) { char sr[32]; if(patrep("ab=len(\"bcd\");","?2=*(*);","name: $0, func: $1, arg: $2",sr,32)!=-1) printf("%s\n",sr); return 0; } |
No.17204![]() |
Re:2バイト文字対応の検索 投稿者---西園寺(2004/10/10 08:52:49) |
||
コメントが全然ないもんだから、ぱっと見ただけじゃさっぱり分かりません。。。 他人に見てもらおうというのであれば、せめて ・各関数の概要と引数の説明 ・for()ループで何をしているか くらいは書いて欲しいです。 #最近、コードの読解力が落ちてる気がする。年かなぁ…(;_;) |
No.17207![]() |
Re:2バイト文字対応の検索 投稿者---Sciggepy(2004/10/10 11:33:00) |
||
すみません。コメントを追加しました。 struct prds { const char *fs; //埋め込むパターン部分の文字列の先頭 unsigned len; //長さ } prdata[10]; unsigned nprd; //パターン部分のインデックス($nのn) //prdataに値を設定 #define prd_set(f,l,n) {prdata[n].fs=(f); prdata[n].len=(l);} //prdataに値を挿入 void prd_insert(const char *f,unsigned l,unsigned n) { unsigned i; for(i=n;i<9;i++) prdata[i+1]=prdata[i]; prd_set(f,l,n); } //パターン照合+prdataの設定 //str: 文字列 //pat: パターン // ?: 任意の1文字 ?n: 任意のn文字(n=0はn=1と見なす) // *: 任意の文字列 \: 直後の文字をただの文字として扱う int patmatch(const char *str,const char *pat) { const char *fs; unsigned long c,i,nd; for(;;) switch(*pat) { case '\0': return *str==*pat; case '\\': if(*(str++)!=*(++pat)) return 0; pat++; break; case '?': if(!(c=strtoul(++pat,(char **)&pat,10))) c=1; for(i=0;i<c;i++,str++) if(*str=='\0') return 0; if(nd<10) prd_set(str-i,i,nprd); nprd++; break; case '*': //ndに挿入位置を保持して*以降を照合 for(fs=str,pat++,nd=nprd,i=0;*str;str++,i++) if(patmatch(str,pat)) { prd_insert(fs,i,nd); nprd++; return 1; } if(*str==*pat) { //*str=='\0' prd_insert(fs,i,nd); nprd++; return 1; } return 0; default: if(*(str++)!=*(pat++)) return 0; } } //パターン置換 //opt: 出力形式 // $n(0=<n=<9): 先頭からn+1番目のパターン部分の文字列 // $$: $ //ret: 戻り値を格納する領域の先頭 //cmax: 最大文字数('\0'を含む) //plen: 格納された文字数 int patrep(const char *str,const char *pat,const char *opt,char *ret,unsigned cmax,unsigned *plen) { unsigned i,j,len; for(i=0;i<10;i++) prd_set(NULL,0,i); //prdataを0で埋める nprd=0; //nprdを0に設定 if(patmatch(str,pat)) { for(i=nprd;i<10;i++) prd_set(NULL,0,i); for(i=0,len=0;opt[i];i++) { if(opt[i]=='$') { if(opt[++i]=='$') { if(len>=cmax-1) break; ret[len++]='$'; } else if((opt[i]>='0')||(opt[i]<='9')) { struct prds *pd; pd=&prdata[opt[i]-'0']; //prdataの要素を参照 for(j=0;j<pd->len;j++) { //文字列を追加 if(len>=cmax-1) break; ret[len++]=pd->fs[j]; } } } else { if(len>=cmax-1) break; ret[len++]=opt[i]; } } ret[len]='\0'; if(plen) *plen=len; return 1; //パターンにマッチした } return 0; //パターンにマッチしなかった } |
No.17205![]() |
Re:2バイト文字対応の検索 投稿者---もぐりん(2004/10/10 10:26:57) |
||
開発環境は? ぱっと見ただけで気づいたことを書きます。 ・unsignedしか書いていない変数は、int型? ・unsignedなのに戻り値が-1なのはなぜ? ・変数ndは値を代入(初期化)していないのに、30行目のif文で 参照している 結構無茶な書き方してませんか? |
No.17206![]() |
Re:2バイト文字対応の検索 投稿者---Sciggepy(2004/10/10 11:05:41) |
||
>・unsignedしか書いていない変数は、int型? そうです。 >・unsignedなのに戻り値が-1なのはなぜ? 0xffffffffのつもりですが、signedとunsignedの比較は変ですね。戻り値は、パターンにマッチしたかどうかを表す真偽値に変えます。 >・変数ndは値を代入(初期化)していないのに、30行目のif文で > 参照している これはnprdの間違いです。 >結構無茶な書き方してませんか? <(~~; |
No.17210![]() |
Re:2バイト文字対応の検索 投稿者---かずま(2004/10/10 16:30:42) |
||
本当は全部書き換えたいけど、最小限の修正に留めておきました。 まだ怪しい部分がありますが、これでいかがでしょうか? #include <stdio.h> #include <stdlib.h> #include <locale.h> struct prds { const char *fs; unsigned len; } prdata[10]; unsigned nprd; #define prd_set(f, l, n) { prdata[n].fs = (f); prdata[n].len = (l); } void prd_insert(const char *f, unsigned l, unsigned n) { unsigned i; for (i = 9; i > n; i--) prdata[i] = prdata[i-1]; prd_set(f, l, n); } int patfind(const char *str, const char *pat) { const char *fs; unsigned long c, i, nd; for (;;) switch (*pat) { case '\0': return *str == *pat; case '\\': c = mblen(++pat, MB_CUR_MAX); for (i = 0; i < c; i++) if (*str++ != *pat++) return 0; break; case '?': c = strtoul(++pat, (char **)&pat, 10); if (c == 0) c = 1; fs = str; for (i = 0; i < c; i++, str += mblen(str, MB_CUR_MAX)) if (*str=='\0') return 0; if (nprd < 10) prd_set(fs, str - fs, nprd); nprd++; break; case '*': fs = str, pat++, nd = nprd; for (i = 0; *str; str += mblen(str, MB_CUR_MAX), i++) if (patfind(str, pat)) { prd_insert(fs, str - fs, nd); nprd++; return 1; } c = mblen(pat, MB_CUR_MAX); for (i = 0; i < c; i++) if (*str++ != *pat++) return 0; prd_insert(fs, str - fs, nd); nprd++; return 1; default: c = mblen(pat, MB_CUR_MAX); for (i = 0; i < c; i++) if (*str++ != *pat++) return 0; } } int patrep(const char *str, const char *pat, const char *opt, char *ret, unsigned cmax) { unsigned i, j, len; for (i = 0; i < 10; i++) prd_set(NULL, 0, i); nprd = 0; if (patfind(str, pat)) { for (i = nprd; i < 10; i++) prd_set(NULL, 0, i); for (i = len = 0; opt[i]; i++) { if (opt[i] == '$') { if (opt[++i] == '$') { if (len >= cmax-1) break; ret[len++] = '$'; } else if (opt[i] >= '0' || opt[i] <= '9') { struct prds *pd = &prdata[opt[i]-'0']; for (j = 0; j < pd->len; j++) { if (len >= cmax-1) break; ret[len++] = pd->fs[j]; } } } else { if (len >= cmax-1) break; ret[len++] = opt[i]; } } ret[len] = '\0'; return len; } return -1; } int main(void) { char sr[256]; setlocale(LC_CTYPE, ""); if (patrep("あい=うえお(\"かきく\");", "?2=*(*);", "name: $0, func: $1, arg: $2", sr, sizeof sr) != -1) printf("%s\n", sr); return 0; } |
No.17224![]() |
Re:2バイト文字対応の検索 投稿者---Sciggepy(2004/10/11 13:13:19) |
||
返信ありがとうございます。 マルチバイト文字も、1文字として数えるほうが便利ですね。 >まだ怪しい部分がありますが、これでいかがでしょうか? やはり、問題になりそうな部分がありますか? |
No.17231![]() |
Re:2バイト文字対応の検索 投稿者---かずま(2004/10/12 11:48:39) |
||
>> マルチバイト文字も、1文字として数えるほうが便利ですね。 ?3 が 3文字でなく 3バイトだとしたら、困りませんか? >> まだ怪しい部分がありますが、これでいかがでしょうか? >> やはり、問題になりそうな部分がありますか? patrep("abcdef", "**", ":$0:$1:", sr, sizeof sr) $0 = "" $1 = "abcdef" patrep("ab-cd-ef", "*-*", ":$0:$1:", sr, sizeof sr) $0 = "ab" $1 = "cd-ef" こういう仕様ということでよいのでしょうか? * が最長一致なら、たとえば後者は $0 = "ab-cd", $1 = "ef" となるはずです。 |
No.17245![]() |
Re:2バイト文字対応の検索 投稿者---Sciggepy(2004/10/12 16:47:48) |
||
patrep("abcdef", "**", ":$0:$1:", sr, sizeof sr) $0 = "" $1 = "abcdef" patrep("ab-cd-ef", "*-*", ":$0:$1:", sr, sizeof sr) $0 = "ab" $1 = "cd-ef" >こういう仕様ということでよいのでしょうか? > >* が最長一致なら、たとえば後者は $0 = "ab-cd", $1 = "ef" となるはずです。 最長一致、最短一致のどちらにしても、必ずしも上手くはいかないので、最短一致のままでよいことにします。 ありがとうございました。 |