Version 11.02
ファイル名を抜き出してみよう
「では今回から実践的な文字列操作についてみていきます」
『はーい』
「まずは、ファイルパスからファイル名だけ抜き出してみます」
『ってゆーと』
C:\Test\Test.txt
『から』
Test.txt
『だけ取り出すってこと?』
「そういうこと。方法はいくらでもあるし、簡単にできる方法もあるんだけ
ど、今回は文字列操作の勉強が目的だから」
『ちょっと難しい方法でする?』
「難しいというよりは、べたな方法っていうか……方針としては」
1:一番最後の \ の位置を求める。
2:そこから最後までを取り出す。
「って感じ」
『一番最後の \ を探すのって、なんかそういうランタイムある?』
「ランタイムにはないね。 CString にはあるけど」
『じゃあ』
「でも今回は使用不可」
『むー』
「オーソドックスな方法だと、後ろからひとつひとつ見ていくって
感じかな。たとえばこんなふうに」
void OutputFileName()
{
char ch[] = "C:\\Test\\Test.txt";
// 後ろから見ていきます。
for( int iIndex = strlen( ch ) - 1; 0 <= iIndex ; iIndex-- )
{
TRACE( "%c\n", ch[iIndex] );
}
}
『 for で……最初に strlen() 、ってことは文字列のサイズ?』
「一番後ろから見ていくから、まずその最後の文字の位置を取っておきま
す。 - 1 してあるのはなんでかわかる?」
『えっと……文字列の長さって確か大きいんだよね。 strlen( "A" ) は 1
だけど、この文字は [0] なんだから』
「そういうこと。まぁ最後の文字は文字列の長さ - 1 って憶えちゃっても
大丈夫だけどね」
『で、これを…… -- でひとつずつ減らしていって、それが 0 以上の間は
ってことね』
「図にすると」
C:\Test\Test.txt
-1 2 5 8 11 14
0 3 6 9 12 15
1 4 7 10 13
『見にくい……』
「う”……ようするに先頭の C は 0 、最後の t は 15 。全部で 16 文字
だから。で、これを実行すると」
t
x
t
.
t
s
e
T
\
t
s
e
T
\
:
C
『後ろから1文字ずつ出力できるわけね』
「 \ の位置は ch[iIndex] が \ だったところだから、ファイル名はその次
の文字からコピーします」
void OutputFileName()
{
char ch[] = "C:\\Test\\Test.txt";
char chOut[MAX_PATH];
// 後ろから見ていきます。
for( int iIndex = strlen( ch ) - 1; 0 <= iIndex ; iIndex-- )
{
if( ch[iIndex] == '\\' )
{
// \\ がみつかりました。
// その次の文字から最後までコピー。
strcpy( chOut, &( ch[iIndex + 1] ) );
break;
}
}
// 出力します。
TRACE( "%s\n", chOut );
}
『 \ と直接比較して、見つかったら……??』
「ここはちょっと難しいかな」
strcpy( chOut, &( ch[iIndex + 1] ) );
『 strcpy() は文字列を右から左にコピーするランタイムだよね。でも、そ
の右っかわがよくわかんない……』
「ひとつひとつ見ていこうか」
ch[iIndex + 1]
『なんで + 1 してんの?』
「だって、 ch[iIndex] の文字は?」
『 \ 』
「そこからコピーしたら \ が入っちゃうでしょ」
『あ! だから次の文字からなんだ』
「そういうこと。じゃ、次」
&( ch[iIndex + 1] )
『 & ……ってことは、アドレス?』
「そういうこと。メモリ上だと」
43 3A 5C 54 65 73 74 5C 54 65 73 74 2E 74 78 74 00
C : \ T e s t \ T e s t . t x t \0
「ってなってるでしょ。最後の \ の右側、つまり」
54 65 73 74 2E 74 78 74 00
T e s t . t x t \0
「が欲しいんだから、この最初の文字のアドレスがわかればいいわけ」
『この最初の文字が ch[iIndex + 1] 、そのアドレスだから & を付けるん
だ』
「そういうこと。で、それを strcpy() でコピーすれば」
『そこから最後までが取り出せて……』
Test.txt
『って出力されるわけねー』
「これはあくまで方法のひとつだし、もちろん CString が使えるならその
メンバ関数を使った方がいいからね」
『はーい』
「で」
『で?』
「こういう関数は、汎用的に色々な場面で使うことになります。文字列処理
ってよくあることだからね」
『だよね、そのたびに1から作ったら大変だもん』
「そのためには文字列を引数として受け取るようにする必要があるね」
『あ、そういえば』
「次に、取り出したファイル名をどう返すかっていう問題があります」
『もんだいなの?』
「大問題。たとえば」
char *OutputFileName()
{
char ch[] = "C:\\Test\\Test.txt";
char chOut[MAX_PATH];
// (略)
return chOut;
}
「が不可なのはわかるよね」
『えっと……あ! chOut って関数の中の変数だから、関数から抜けると
なくなっちゃう! だからそういう変数のポインタを戻り値にしちゃいけな
い! って話だったよね』
「そうそう、 Version 4.13 ( No.063 ) でやったね」
『あ! じゃあ、 strcpy() みたいに、引数で渡してもらってそこにコピー
すればいいんだ』
「そうなるかな。あと、エラーチェックも欠かさずにしないと」
『エラーチェック?』
「渡された文字列ポインタが NULL だったらダメでしょ」
『そういうチェックって必要なの?』
「できるならしておいた方がいいよ。まぁするにしても、エラーがあったと
きにどう処理するかっていうのも考えないといけないけど」
『確かに……』
「他にも、プログラム上問題はないかっていうのも考えないと」
『問題?』
「たとえば」
char ch[] = "C:\\Test\\";
「みたいに、最後に \ があっても大丈夫か? とか」
『え?』
「ほら、 iIndex + 1 ってしてるから、 \ の右側を見るわけでしょ」
『あ!! 配列からはみ出ちゃう!!』
「でも \0 にアクセスするだけだから大丈夫」
『あ……うー、なんかすんごくどきっとしちゃったよ』
「でも strcpy() に \0 の場所渡しても大丈夫かな」
『!!』
「とか、そういうふうに色々検証しなきゃいけない部分があるってこと」
『なんかすんごくドキドキするよー』
「その気持ち、忘れないようにね」
『??』
「変な関数作って迷惑掛けてもいいや、みたいに思わないことが大切だか
ら。あともうひとつ」
char ch[] = "C:\\Test\\ソフト.txt";
「がちゃんと切り取れるかどうか」
『そんなの当たり前じゃげげ!!』
フト.txt
『な、何これ〜 』
「というわけで次回に続く」
/*
Preview Next Story!
*/
『なにこれなにこれ!!』
「ビックリした?」
『ビックリした! なんでこんなんなっちゃうの!?』
「それを次回解説します」
『というわけで次回』
< Version 11.03 Shift JIS >
「につづく!」
『あーもう、ドキっとさせないで!』
「いや、これからそんなの何度もあるし」
『げ』
「それに……ドキっとするだけで済めばいいけど……」