• ベストアンサー

エクセルVBAで特定文字列の個数を高速に調べたい

文字列の入っている変数内で特定の文字列(今回はvbCrLf)が何個発生しているかを、高速に調べたいのですが、どのような方法があるでしょうか? 現在以下のことをやっています。 数千件のテキストファイルから特定文字列を検索しています。 検索を高速化するために、テキストファイルをバイナリーモードで1つの変数に読み込み、instr関数で検索しています。 見つかった場合、その位置から前にあるvbCrLfをInStrRev関数で、後ろにあるvbCrLfをinstr関数で位置を調べ、元の変数からmid関数で該当ラインを取り出しています。 検索はこれで可能ですが、特定文字列を調べたinstr関数の戻り値がテキストファイルの先頭からの位置(何桁目)なので、検索した文字列が何行目にあるか分かりません。 変数の検索文字が見つかった位置までの部分でvbCrLfが何個発生しているかが分かれば行数が判定できます。 vbCrLfを調べるinstr関数を何回も繰り返せば行数の判定は可能ですが、もっと高速に(一つの関数・命令で)調べることはできないでしょうか? また他に行数を特定する良い方法があったら教えてください。 よろしくお願い申し上げます。

質問者が選んだベストアンサー

  • ベストアンサー
  • luan78zao
  • ベストアンサー率55% (19/34)
回答No.1

行数をカウントするだけなら、FileSystemObjectのTextStreamを使用するのが最速だと思います。 改行コード以外の文字をカウントする場合は、RegExpクラスのmatchオブジェクトを使うのがよいと思います。 だいぶ以前に検証↓したことがありますので、ご参考まで。 http://fukkey.dyndns.org/pins/vb/021115/45028.html

参考URL:
http://fukkey.dyndns.org/pins/vb/021115/45028.html
believe_me
質問者

お礼

回答ありがとうございました。 RegExp、ヒントになりました。 > 改行コード以外の文字をカウントする場合は、 > RegExpクラスのmatchオブジェクトを使うのが > よいと思います。 とのことですが、改行コードをカウントできました。 RegExpオブジェクトのPatternプロパティにvbCrLfを指定し Executeメソッドを実行し、MatchesコレクションのCount プロパティでvbCrLfの個数が分かりました。 FileSystemObjectのTextStreamはテキストファイルの全行数を調べる ように思えますが、いかがでしょうか。 知りたいのは全行数ではなく、該当文字列のあった行です。 いずれにしても、先のMatchesコレクションで分かったvbCrLfの個数で ラインが割り出せますので問題ありません。

その他の回答 (6)

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.7

こんにちは。Wendy02です。 >数千本のプログラムソースコード(即ちテキストファイル)があります。(既に存在しています) 私には、believe_meさんが、どういうご事情があるのか分かりませんが、失礼ですが、プロの方ではありませんか?私などアマチュアがあれこれ言える立場ではないかもしれませんが、わざわざ、アマチュアの使うOffice VBAなどは必要ないような気がします。 >全ソースコードを調べ、その項目名が使われるプログラム名(即ちファイル名)とその個所(何ライン目)の一覧表を作成する必要があります。 それは、Win では、Grep(GNUで、オープンソース付き)が一番なのです。しかし、それがダメなら、Grepの代わりに、擬似Grepの FindStr を使えばよいと思います。お仕事の立場上、手取り足取りのコードを書く必要はないと思いますから、すべてを書きませんが、以下のようなコードで取れます。後は、ファイル名:行数:内容 で、区切り文字が「:」ですから、それを、Split で区切れば、Excelのセルに取り出せます。 以前、私が作った検索プログラムを応用すれば、以下のようなコードになります。これは、テキスト出力までです。 ただし、以下は、Win2x系のみです。 Const QT As String = """" Const OUTFNAME As String = "$SearchList.txt" Const SEARCHWD As String = "RegExp" 'RegExpを探す Cmd = "FindStr /rni " 'r =正規表現,n=行番号表示,i=大文字小文字無視 OutDir = ThisWorkbook.Path & "\" 'FILENAMEは、ワイルドカードが使えます。 "スペースがなければ、FILENAMEの前後のQT は、いらないです。 ret = Shell("CMD /C" & Cmd & " " & SEARCHWD & " " & QT & FILENAME & QT & " > " & QT & OutDir & OUTFNAME & QT) それを、テキスト出力して、ファイル名と行数が出てきますから、それをExcelで拾いだせばよいと思います。ただし、Win9x 系は #6のvenzoさんのFind ですが、正規表現が機能には含まれません。また、Cmd は、Command.com に換わります。

believe_me
質問者

お礼

>失礼ですが、プロの方ではありませんか? メインフレームのプロ(SE)です。 PC、エクセル、VBAは独学で、これで食っていける技能はありません。 現在の職場には最近配属されたばかりで、非常にセキュリティに厳しいところです。 守秘義務があるので詳しいことは言えませんが、企業の置かれた社会的立場からやむを得ない措置だと思っています。 メインフレームが自由に使えるなら、パワーのあるマシンですべてやってしまいますが、メインフレームの使用もかなり制限されています。 PCの使用もかなり制限されていますが、幸いVBAだけは自由に使える環境です。 そこでこれを活用して、仕事を効率アップを考えたわけです。 実はこの質問に対する回答はNo.1の方で解決済みですが、他にも良い方法がないかと締め切りませんでした。 皆様から色々ご助言いただきありがとうございました。

noname#22650
noname#22650
回答No.6

>使いたいのは山々ですが、職場はセキュリティが厳重で外部プログラム(grepなど)のインストールは一切できません。 忘れてましたが、widows標準で、findと言うコマンドがあります。 私は使ったこと無いのですが、これが使えるかもしれませんね。 以下findのヘルプ >find /? ファイル (複数可) 内のテキスト文字列を検索します。 FIND [/V] [/C] [/N] [/I] [/OFF[LINE]] "文字列" [[ドライブ:][パス]ファイル名[...] ] /V 指定した文字列を含まない行をすべて表示します。 /C 指定した文字列を含む行の数だけを表示します。 /N 行番号を表示します。 /I 大文字と小文字の区別をしないで検索します。 /OFF[LINE] オフライン属性が設定されたファイルをスキップしません。 "文字列" 検索する文字列を指定します。 [ドライブ:][パス]ファイル名 検索するファイル (複数可) を指定します。 パスが指定されていないときは、プロンプトで入力されたテキストまた は別のコマンドからパイプ処理で渡されたテキストを検索します。

noname#60992
noname#60992
回答No.5

素人の考えですが、 splitとか使って配列に格納するのでは遅すぎますか?

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.4

こんばんは。#3のWendy02です。 >使いたいのは山々ですが、職場のセキュリティが厳重で所定のプログラム以外は一切インストール・実行できません。 私も、仕事でHDDの文書検索はしますが、VBAは、実際の仕事では使いません。失礼かもしれませんが、それは、質問者さん個人の問題ではなくて、会社の生産性の問題です。セキュリティがどうこうの問題じゃないのですけれどね・・・。もし企業だったら、この程度の問題に対応できないようなら、どうしようもないと思います。まあ、自分の置かれた立場の問題もありますから、場合によっては、最初から最後まで黙して語らずということもありますけれど。 ただ、もう一度、ご質問を最初から読みましたが、「行数の判定」ということでしょうか?「行数の判定」だけだったら、正規表現などいりませんよ。 単に、ファイルを開いて、ファイルをAppendモードで開いて、その最後の行を取ればよいです。FILENAME は、Dir のループで入れるなりしてください。 Set objFs = CreateObject("Scripting.FileSystemObject") Set objText = objFs.OpenTextfile(FILENAME, 8) 'Append モード  MsgBox objText.Line  objText.Close Set objFs =Nothing それに、文字列検索だったら、Grepの代わりに、FindStr を使えばよいです。 ただ、Unix 系ツールの方がずっと楽なことは言うまでもないです。 #1のお礼の >知りたいのは全行数ではなく、該当文字列のあった行です。 ご質問の趣旨が、良く分かりません。

believe_me
質問者

補足

回答ありがとうございます。 提示していただいたVBAはテキストファイルの行数を表示するものですね。 私が知りたいのは、やはり次の通りです。 >知りたいのは全行数ではなく、該当文字列のあった行です。(先頭から何ライン目か) >ご質問の趣旨が、良く分かりません。 質問が言葉足らずだったかも知れません。 具体的には、テキストファイルの中身はプログラムのソースコードです。 やりたいことは以下の通りです。 数千本のプログラムソースコード(即ちテキストファイル)があります。(既に存在しています) システム開発は標準化されていて、すべてのプログラムで項目名は統一されています。 システムメンテがある項目に対して発生した場合、対応する可能性のあるプログラムと使用されている個所を特定せねばなりません。 全ソースコードを調べ、その項目名が使われるプログラム名(即ちファイル名)とその個所(何ライン目)の一覧表を作成する必要があります。 以上ですが、お分かりいただけましたでしょうか。

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.3

こんにちは。 それは、Namazu とか、専門システムを使ったほうが早いです。 それに、その作業のことを、KeyWord In Context いわゆる KWIC といいます。専用ツールを使ったほうが良いです。例えば、コンコーダンスを作成する時や、大学などで文献検索に使うシステム・ツールです。Grep(GNUに限ります)も同じUnix系のツールですが、それをさらに文献検索用に発展させたものです。

believe_me
質問者

お礼

回答ありがとうございます。 使いたいのは山々ですが、職場のセキュリティが厳重で所定のプログラム以外は一切インストール・実行できません。 使えるのはOfficeくらいなものです。インターネットにもアクセスできません。

noname#22650
noname#22650
回答No.2

速さにこだわるなら、外部プログラム(grepなど)で検索する方が良いかと思います。 Shell "cmd.exe /C ""grep.exe >search.log""" 検索結果をリダイレクトでファイルにして、それを解析する。 速さは、エクセルVBA(インタプリタ)とは比べものにならないと思いますよ。 コマンドライン用の検索プログラムは"grep"が有名です。 UNIX系のコマンドの移植なので、幾つかバージョンが有ったり、同名の類似品があったりします。 http://www.vector.co.jp/soft/winnt/util/se365621.html http://www.vector.co.jp/soft/win95/util/se015011.html grep以外でもフリーのものはあると思うので、使いやすそうなものを探してみてはいかがでしょう。

believe_me
質問者

お礼

回答ありがとうございます。 使いたいのは山々ですが、職場はセキュリティが厳重で外部プログラム(grepなど)のインストールは一切できません。