C言語(win32api)で文字列の置換。改善の余地あり
2015/07/06
コピー → 置換 → ペースト。
ある文字列をコピーした際、既定した文字列で自動で置換し、そのまま貼る。
例えば、
大なり(>)や小なり(<)を含む文章を投稿するとき、それらをコピペすると自動でエスケープ文字に変換するといったことを自分でやってみたかった。
機能としてはしょぼいけど、とりあえず置換の流れとしてはこんな感じ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
#pragma comment(lib,"Shlwapi.lib") ←これがないとコンパイルが通らなかった #include <Windows.h> #include <Shlwapi.h> /* srcの先頭からsubを探し、最初に見つけたものをrepに置き換える。2番目などの指定は出来ない 置き換えが発生しない場合、NULLを返す。返却されるポインタは使用後解放すること 戻り値じゃなくて引数に格納するためのポインタを取得した方がいいのか? 戻り値は置換の有無を返すとか */ LPTSTR strReplace(LPCTSTR src, LPCTSTR sub, LPCTSTR rep){ int srcl, subl, repl, pos; LPTSTR replaceStr, pchar; // subの方が大きい場合、一致することはない。NULL if( (srcl = lstrlen(src)) < (subl = lstrlen(sub)) ) return NULL; // subが指定されていないときはNULL if( subl==NULL ) return NULL; // subとrepが同じ場合何もしない。NULL if( lstrcmp(sub,rep)==0 ) return NULL; // 検索して一致しない場合、NULL if((pchar = StrStr(src,sub)) == NULL) return NULL; // 一致した場所のインデックス pos = (pchar - src); // 置き換える文字列の文字数 repl = lstrlen(rep); /* コピー */ // 最終的に必要な量のメモリを確保、終端文字(+1)まで replaceStr = (LPTSTR)malloc((srcl-subl+repl+1)*sizeof(TCHAR)); // 一致部分までの文字列をコピー memmove(replaceStr, src, pos*sizeof(TCHAR)); // 置き換える文字列をコピー memmove(replaceStr+pos, rep, repl*sizeof(TCHAR)); // 終端まで memmove(replaceStr+pos+repl, src+pos+subl, (srcl-pos-subl+1)*sizeof(TCHAR)); return replaceStr; } /* srcの先頭からsubを探し、全てrepに置き換える。malloc,freeの繰り返しなので効率は酷そう あらかじめ、すべて置換したときのメモリを計算して一回だけ確保するようにした方がよさそう */ LPTSTR strReplaceAll(LPCTSTR src, LPCTSTR sub, LPCTSTR rep){ LPTSTR str,tmp; str = strMallocCpy(src); while( (tmp=strReplace(str,sub,rep)) != NULL ){ if(str!=NULL); free(str); str = tmp; } return str; } // 文字列を複製して返す LPTSTR strMallocCpy(LPCTSTR src){ LPTSTR str = (LPTSTR)malloc((lstrlen(src)+1)*sizeof(TCHAR)); lstrcpy(str, src); return str; } |
とりあえず、今の知識で作ってみた。
もっと安全性や効率などは上げられると思うけど、とりあえず動いたから今はいいや。
普段はJavaなので、mallocとかfreeとかの使い方に不安が拭えない。memmoveとかもなんとなく怖い。
文字の扱いが大変。関数の使い方はこれでいいのか?
もっと色々な言語を学んだ方がいいとは思っているけど、なかなか続かない。
Rubyとかにもちょっと手を出してみたけど、もう忘れた・・・
この本はなかなか面白かった。
どうして if文 などの文法ができたのか。エラー処理とかいう面倒なものはなぜ出来たのか?ちゃんと意味があったんだということが分かり面白かった。
プログラミング初心者の人は読んでみるのもいいと思います。
追記
一括置換のプログラムを書き換えてみた。
最初に置換文字列が何個含まれるか確認し、メモリの確保を1回にした。
とりあえず、速度は速くなった。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
LPTSTR strReplaceAll(LPCTSTR src, LPCTSTR sub, LPCTSTR rep){ LPTSTR pstr; // 最終的に置き換えた文字列を格納。戻り値 LPTSTR pSrcEnd; // StrStr(src,sub)の結果 int pos=0; // pstrの書き込み位置のインデックス int srcF=0; // srcの読み取り範囲のインデックス、ここから int srcE; // srcの読み取り範囲のインデックス、ここまで int srcl, subl, repl; // 各文字列の長さ(lstrlenの値) int num=0; // 置き換え回数 // subの方が大きい場合、一致することはない if( (srcl = lstrlen(src)) < (subl = lstrlen(sub)) ) return NULL; // subが指定されていないとき if( subl==0 ) return NULL; // subとrepが同じ場合何もしない if( lstrcmp(sub,rep)==0 ) return NULL; /* 一致する回数を数える */ pSrcEnd = StrStr(src,sub); while(pSrcEnd!=NULL){ num++; pSrcEnd = StrStr(pSrcEnd+1,sub); } if(num==0) // 一度も一致しないときはNULL return NULL; repl = lstrlen(rep); // 全て置換し終えた時に必要なメモリを確保する。 pstr = (LPTSTR)malloc((srcl+1+(repl-subl)*num)*sizeof(TCHAR)); srcE = -1; // 計算の都合 // 置換文字列がある限り繰り返す while( (pSrcEnd=StrStr(src+srcE+1,sub))!=NULL ){ srcE = pSrcEnd - src; // コピーするインデックス位置、ここまで memmove(pstr+pos, src+srcF, (srcE-srcF)*sizeof(TCHAR)); pos += (srcE-srcF); memmove(pstr+pos, rep, repl*sizeof(TCHAR)); pos += repl; srcF = srcE + subl; } // 最後の部分をコピー memmove(pstr+pos, src+srcF, (srcl-srcF+1)*sizeof(TCHAR)); return pstr; } |
メモリ確保の際、終端文字分(+1)を忘れることが結構あるので注意したい。
関連記事
-
「>」、「<」を含む文字列をコピーしたら自動でエスケープ文字にするアプリを作った
以前、文字列置換の記事でちょこっと書いたものを実際に作ってみた。クリップボードの …
-
Unicode?Ansi?Windowsでの文字列の表現が紛らわしい
エディットコントロールを作る際に「文字列リテラル」について考えたこと。 定義した …
-
エディットコントロールにクリップボードの内容を出力してみた
今回はテキスト入力を処理する「エディットコントロール」を作ってみた。 前回取得し …
-
クリップボードの内容を取得しよう→_crtisvalidheappointerエラーで落ちる
前回の記事でClipboardを取得する際に発生したエラーについて こちらのペー …
-
クリップボードの内容を取得してみた
何を書けばいいのかわからなくなってきた。 行動指針が見つからない。今、自分は何を …
スポンサーリンク
週間人気記事
Android Serviceのメモ。onBind,onRebind,onUnbindが呼ばれる条件
AndroidStudioでコピペする方法。デフォルトではクリップボードから貼り付けできない
[Win]+[Print]知らなかった。スクショってそのまま保存出来たんだ。