中身がテキストのファイルを文字列検索するには?

解決


プログラム初心者  2006-12-05 13:18:18  No: 63830

始めまして。
VC.NET(VS.NET2003、OS:WinXP Pro SP2)で、中身がテキストのファイルかどうかを確認し、もしそうだったら、文字列を検索して、見つかった場合はその行またはファイル名を返すようなプログラムを作りたいと思っています。

そこで教えていただきたいことが2点あります。
一つ目は、「中身がテキストのファイルかどうかを確認」することは可能なのでしょうか?
拡張子が「txt」出なくても、中身がテキストだったりするファイルってたくさんありますよね?

もう一つは、そのテキストファイルに文字列が含まれているかをチェックするような関数って存在するのでしょうか?
C言語の関数になっちゃいますが、標準出力でprintfにたいしてfprintfというファイル出力関数がありますよね?
これと同じのりでstrstrに対してfstrstrってないのかな?とライブラリ
(VSのHelp)をキーワードで検索すると・・・項目としては見つかるのですが、開いてみるとstrstr関連の説明で、fstrstrという関数の名前は本文のどこにも現れませんでした・・・
そもそもfstrstrって、存在するんですか?

なんか変な質問してたらごめんなさい。
御存知の方いらっしゃいましたら、教えていただけませんでしょうか?


Ban  2006-12-05 17:51:58  No: 63831

> 一つ目は、「中身がテキストのファイルかどうかを確認」することは可能なのでしょうか?

完全な方法はないです。読んでみて、読めたらテキストです。

> そもそもfstrstrって、存在するんですか?

標準にはないです。


tetrapod  2006-12-05 17:52:01  No: 63832

テキストファイルって何?を定義することからはじめる必要がありそう。
日本語のファイルは米人にはバイナリにしか見えないだろうし
EUC/UTF のファイルは SJIS 解釈するとバイナリにしか見えないだろうし
EBCDIC テキストは ASCII ではバイナリにしか見えないだろうし

ということで

>「中身がテキストのファイルかどうかを確認」することは可能?
「テキストファイル」の定義次第。一般的には無理。
>そもそもfstrstrって、存在するんですか?
無い。そもそもC/C++の文字列ってのは単にcharの列でしかない。
その「char の列」が人間に可読かどうかは問わないわけで
「テキストファイル=人間に可読」とは無関係。

もうちょっと案件を絞ってほしいな。
まずはどういう条件であれば「テキストファイル」であるかを決めてくれ。
そしたら少しはアドバイスできるかもしれない。


tetrapod  2006-12-05 19:18:19  No: 63833

テキストファイルから任意文字列の検索をするだけなら、わざわざ自作しなくても
grep (UNIX/Cygwin) とか find (Windows) とかが使える。

使う(=検索する)のが目的なら車輪の再実装する必要はない
作る(=勉強する)のが目的なら、まあがんばってくれ


夏みかん  2006-12-07 10:54:36  No: 63834

私もテキストファイルかバイナリファイルの判定はよく処理します。
そこで、普段利用している判定用の関数をご紹介します。参考にしてね。
なお、ファイルの先頭 1024 バイトだけで判定しています。

/* このファイルで使用する関数 */
#define MacroLoadFile(s,a)    CreateFile((LPCTSTR)(s),(GENERIC_READ|GENERIC_WRITE),(FILE_SHARE_READ|FILE_SHARE_WRITE),NULL,OPEN_EXISTING,a,NULL)

/* このファイルで使用する定数 */
#define BEL    (0x07)
#define BS    (0x08)
#define ESC    (0x1B)

/* バイナリ・ファイルの判別関数 */
extern BOOL CheckBinFile( LPCTSTR lpBuff, DWORD dwSize )
{
  DWORD dwData;
  
  for ( dwData = 0 ; dwSize != 0 ; dwSize--, lpBuff++ ){
    if ( iscntrl(*lpBuff) && !isspace(*lpBuff) ){
      if ( (*lpBuff != BS) && (*lpBuff != BEL) && (*lpBuff != ESC) ){
        dwData++;
      }
    }
  }
  return( dwData ? TRUE : FALSE );
}
/*
●引数/戻り値
①lpBuff には、判定するデータ領域を指定する。
②dwSize には、判定するデータ容量を指定する。
③戻り値は、バイナリ・ファイルなら TRUE を、そうでなければ FALSE を返す。
※制御文字の範囲で、空白文字と BS / BEL / ESC 文字以外ならバイナリと判定する。
※空白文字とは、TAB LF VT FF CR の 5 つです(^I ^J ^K ^L ^M)
※BS  文字とは、0x08 のバックスペースです。
※BEL 文字とは、0x07 のベルコードです。
※ESC 文字とは、0x1B のエスケープシーケンスです。
※BS / BEL / ESC 文字があってもバイナリとは判定しないのは、バッチファイルで
  よく利用されるためです。それ以外は、バイナリファイルの可能性が高いです。
*/

/* ファイル・データの種類をチェック */
extern INT FileCheck( LPCTSTR lpFname, DWORD dwAttrib )
{
  INT nSuccess = 0;
  TCHAR szBuff[ 1024 ];  ←先頭 1024 バイトで判断(可変可能)
  DWORD dwSize;
  HANDLE hFile;
  
  if ( (hFile = MacroLoadFile(lpFname,dwAttrib)) != INVALID_HANDLE_VALUE ){
    if ( (dwSize = GetFileSize(hFile,NULL)) > sizeof(szBuff) ){
      dwSize = sizeof( szBuff );
    }
    if ( ReadFile(hFile,szBuff,dwSize,&dwSize,NULL) != FALSE ){
      if ( CheckBinFile(szBuff,dwSize) ){
        nSuccess = -1;    // バイナリファイル
      }
      else{
        nSuccess = +1;    // テキストファイル
      }
    }
    CloseHandle( hFile );
  }
  return( nSuccess );
}
/*
●引数/戻り値
①lpFname には、ファイル名の文字列を指定する。
②dwAttrib には、ファイルの属性を指定する。(通常は FILE_ATTRIBUTE_NORMAL を指定)
③戻り値は、テキストファイルなら +1、バイナリファイルなら -1、そしてファイルが
  読み込めなければエラーとして 0 を返す。
*/


プログラム初心者  2006-12-09 12:01:09  No: 63835

こんばんは。
インフルエンザでダウンし、しばらく見ていない間に・・・こんなにレスいただいていて・・・ありがとうございます!!

UNIXのgrepは知っていましたが、WindowsのfindはUNIXのfindと混同していて、テキストの検索とは知りませんでした(^^;

でもtetrapodさんが言っている「文字コード」はちょっと気になりました。
例えば、単純にファイルを開いたときに、例えばそのファイルの中身がテキスト形式だったとして、文字コードはどこで判別してるんですかね?
極端な話、複数の(中身がテキストである)ファイルから検索するときに、JIS、SJIS、EUCのファイルがそれぞれあって、どの文字コードだろうと気にせず検索するのって、非常に難しそうですね・・・。

↑あ、これ、今回やりたいこととはかけ離れているので・・・

夏みかんさんのソースも参考にしながら、頑張ってみます☆
とりあえず、中身がテキストかを判別しないでファイル中に検索したい文字列があればそのファイル名と行数を返すところまでは作れた(自分が作成したテキストファイルなどでやって見て結果が出せました)ので、夏みかんさんのコードをじっくり見て、内容を理解しながら実装できればと思います。

ありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加