質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.60%

テキストファイルから欲しい文字列を抽出したいのですが、時間がかかってしまいます。

解決済

回答 5

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 12K+

sumire_cl

score 213

 前提・実現したいこと

けっこう長いテキストファイルがいくつかあります。(1MB超えてるのが普通)
このなかのところどころに
busho('code001','部署名','担当者');
という記述があって
そこの部署コードと部署名と担当者が書いてあるところだけ集めたいのです。

 書いたコード

Sub getBusho()

Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")

Dim sBuf As String
With fso.GetFile("C:\(フルパス)\text.txt").OpenAsTextStream
    sBuf = .ReadAll
    .Close
End With

Dim i As Long
Dim j As Long
Dim k As Long:  k = 1
Dim tmpBuf As String
For i = 1 To Len(sBuf)-6 Step 1
    If Mid(sBuf, i, 6) = "busho(" Then
        j = i
        tmpBuf = ""
        Do While Mid(sBuf, j, 2) <> ");" And j < Len(sBuf) - 6
            tmpBuf = tmpBuf & Mid(sBuf, j, 1)
            j = j + 1
        Loop
        Cells(k, 1) = tmpBuf
        k = k + 1
    End If
Next i

End Sub


取れるんですけど
めっちゃ時間かかります……。

これは何が悪くて時間がかかるのでしょうか。
無駄な処理があるのでしょうか。

 補足情報(FW/ツールのバージョンなど)

Excel2016で、Windows10です。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • alg

    2018/11/16 18:31

    まず、「書いたコード」のどのステップが遅いのか、計測するべきかと思われます。

    キャンセル

  • sumire_cl

    2018/11/16 18:48

    計測!計測ってどのようにするのですか?そこからかよ!って感じでしょうが、すみませんそこからです……。

    キャンセル

  • papinianus

    2018/11/16 21:59

    誰か計測方法くらい教えたげてよ。http://officetanaka.net/excel/vba/tips/tips161.htm

    キャンセル

回答 5

checkベストアンサー

+1

重くなる原因として推測されるのは、

  1. ループで一文字分ずつ移動して検索している、
    文字数分のループが発生するので大きなテキストだと重くなる

  2. 条件合致部分のテキストを取り出すのに、一文字ずつ連結している、
    文字列連結の繰り返しは重くなる原因です。

  3. 検索結果をセルに一個ずつ代入している、
    その都度、再描画が発生するので結果件数が多いと重くなります。

前2つのの改善策としては、Instrを使うといいでしょう。

最後の原因の改善策は、検索結果を配列に格納して、最後に一気にセルに代入するといいでしょう。

ちなみに、数MBぐらいのテキストなら、1行ずつ読み込みより、一気に読み込んだ方が速いと思います。
(現在のPCのRAMは数GBが普通なので)

上記の改善策を適用させたコード例

Sub getBusho_Kai()

    Application.ScreenUpdating = False
    Dim fso As Object
    Set fso = CreateObject("Scripting.FileSystemObject")

    Dim sBuf As String
    With fso.GetFile("C:\TEST\Test.txt").OpenAsTextStream
        sBuf = .ReadAll
        .Close
    End With

    Dim k As Long: k = 0
    Dim p1 As Long: p1 = 1
    Dim p2 As Long
    Dim tmpBuf As String
    Dim ary()
    Do
        p1 = InStr(p1, sBuf, "busho(")
        If p1 = 0 Then Exit Do
        p2 = InStr(p1, sBuf, ");")
        If p2 = 0 Then Exit Do
        tmpBuf = Mid(sBuf, p1, p2 - p1 + 2)
        p1 = p2 + 2

        ReDim Preserve ary(k)
        ary(k) = tmpBuf
        k = k + 1
    Loop

    Range("A1").Resize(UBound(ary) + 1).Value = WorksheetFunction.Transpose(ary)
    Application.ScreenUpdating = True

End Sub

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/17 00:18

    他のかたの回答にもInStrを教えてくださったかたがいらっしゃったのですが
    InStrだとなんで速くなるのかなというところがわからなかったのです。
    そうか、これだと
    私のだとループ回数は文字数ぶんですが
    これだとbumonの数だけになるので、
    回数が大幅に減ることになるわけですね!
    性能ショボめのPCなので、ループ回数の差は顕著に出ると思います。

    文字列連結は考え方が簡単なため結構頻繁に使ってしまうので、考えを改めようと思います。
    3は配列でもいいし、ttyp03さんが教えてくださった描画OFFでも大丈夫そうな気がします。

    皆様ありがとうございます、勉強になりました!

    キャンセル

  • 2018/11/17 11:00

    私も通常は描画OFFだけでいいと思います。それでもまだ重くて改善したいというときに配列を使うといいでしょう。配列で速度を改善するという手段は覚えておくといろいろ使える場面があると思います。

    キャンセル

0

InStr関数を使った方が良いです。
http://www.officetanaka.net/excel/vba/function/InStr.htm

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

確かに時間がかかりそうな処理に見えたので、実際にやってみました。
約4Mのテキストファイルに1000行ほどbushoの行を突っ込んでみました。
環境は、Excel2013+Windows7なので異なります。
結果、1秒強で終わりました。

bushoのデータがもっと大量にあるのなら、画面描画を抑制すると速くなる可能性はあります。
関数の始めと終わりで、Application.ScreenUpdatingを設定してみてください。

Sub getBuso()
    Application.ScreenUpdating = False
~
    Application.ScreenUpdating = True
End Sub

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/16 22:12

    1秒… 私はもっとかかります。PCショボいというのも大きな原因のひとつのような気がしました…

    キャンセル

  • 2018/11/16 22:18

    bushoは何個くらいあるんですか?

    キャンセル

  • 2018/11/17 00:21

    テキストによって
    ほとんど入ってないこともあるし
    数百個くらいのときもあります。
    大きくていっぱいあるときは、やっぱりちょっと待つ感じです。

    キャンセル

0

とりあえず出力をテキストファイルにしてみたらどうスか?

ついでに、(参考までに) VBScript で大まかなとこ書いときます。

Option Explicit
Dim objF,args,outf,outp,outs,inp
Set objF = CreateObject("Scripting.FileSystemObject")
Set args = WScript.Arguments

If args.count = 0 Then
  MsgBox "TXTファイルをドロップしてください。"
  WScript.Quit
End If

outf = objF.GetParentFolderName(args.item(0)) & "\hoge.txt"
Set outp = objF.OpenTextFile(outf,2,True)

If Ucase(objF.GetExtensionName(args.item(0))) = "TXT" Then
  Set inp = objF.OpenTextFile(args.item(0),1)
  Do Until inp.AtEndOfStream

    ' inp.ReadLine で一行読み込み
    ' 一行分の処理

    ' outp.WriteLine 出力内容
  Loop
  inp.Close
  Set inp = Nothing
End If

outp.Close
Set outp = Nothing
Set objF = Nothing
MsgBox "おわりました。"

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

一回ファイルを全部読んでから順次やっているから、というのが遅い原因の一旦かも知れません。

takasima20 さんの書いたように、1行ごとに読んで解釈して、の方が(メモリを食わないし)良いかと思います。
※行をまたがないことが条件になりますが

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.60%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • トップ
  • VBAに関する質問
  • テキストファイルから欲しい文字列を抽出したいのですが、時間がかかってしまいます。