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

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

新規登録して質問してみよう
ただいま回答率
85.48%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Q&A

解決済

5回答

35293閲覧

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

sumire_cl

総合スコア228

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

0グッド

0クリップ

投稿2018/11/16 07:06

編集2018/11/16 11:35

前提・実現したいこと

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

書いたコード

VBA

1Sub getBusho() 2 3Dim fso As Object 4Set fso = CreateObject("Scripting.FileSystemObject") 5 6Dim sBuf As String 7With fso.GetFile("C:(フルパス)\text.txt").OpenAsTextStream 8 sBuf = .ReadAll 9 .Close 10End With 11 12Dim i As Long 13Dim j As Long 14Dim k As Long: k = 1 15Dim tmpBuf As String 16For i = 1 To Len(sBuf)-6 Step 1 17 If Mid(sBuf, i, 6) = "busho(" Then 18 j = i 19 tmpBuf = "" 20 Do While Mid(sBuf, j, 2) <> ");" And j < Len(sBuf) - 6 21 tmpBuf = tmpBuf & Mid(sBuf, j, 1) 22 j = j + 1 23 Loop 24 Cells(k, 1) = tmpBuf 25 k = k + 1 26 End If 27Next i 28 29End Sub

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

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

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

Excel2016で、Windows10です。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

alg

2018/11/16 09:31

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

2018/11/16 09:48

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

回答5

0

ベストアンサー

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

  1. ループで一文字分ずつ移動して検索している、

文字数分のループが発生するので大きなテキストだと重くなる

  1. 条件合致部分のテキストを取り出すのに、一文字ずつ連結している、

文字列連結の繰り返しは重くなる原因です。

  1. 検索結果をセルに一個ずつ代入している、

その都度、再描画が発生するので結果件数が多いと重くなります。

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

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

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

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

vba

1Sub getBusho_Kai() 2 3 Application.ScreenUpdating = False 4 Dim fso As Object 5 Set fso = CreateObject("Scripting.FileSystemObject") 6 7 Dim sBuf As String 8 With fso.GetFile("C:\TEST\Test.txt").OpenAsTextStream 9 sBuf = .ReadAll 10 .Close 11 End With 12 13 Dim k As Long: k = 0 14 Dim p1 As Long: p1 = 1 15 Dim p2 As Long 16 Dim tmpBuf As String 17 Dim ary() 18 Do 19 p1 = InStr(p1, sBuf, "busho(") 20 If p1 = 0 Then Exit Do 21 p2 = InStr(p1, sBuf, ");") 22 If p2 = 0 Then Exit Do 23 tmpBuf = Mid(sBuf, p1, p2 - p1 + 2) 24 p1 = p2 + 2 25 26 ReDim Preserve ary(k) 27 ary(k) = tmpBuf 28 k = k + 1 29 Loop 30 31 Range("A1").Resize(UBound(ary) + 1).Value = WorksheetFunction.Transpose(ary) 32 Application.ScreenUpdating = True 33 34End Sub

投稿2018/11/16 12:40

編集2018/11/16 12:57
hatena19

総合スコア33715

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sumire_cl

2018/11/16 15:18

他のかたの回答にもInStrを教えてくださったかたがいらっしゃったのですが InStrだとなんで速くなるのかなというところがわからなかったのです。 そうか、これだと 私のだとループ回数は文字数ぶんですが これだとbumonの数だけになるので、 回数が大幅に減ることになるわけですね! 性能ショボめのPCなので、ループ回数の差は顕著に出ると思います。 文字列連結は考え方が簡単なため結構頻繁に使ってしまうので、考えを改めようと思います。 3は配列でもいいし、ttyp03さんが教えてくださった描画OFFでも大丈夫そうな気がします。 皆様ありがとうございます、勉強になりました!
hatena19

2018/11/17 02:00

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

0

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

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

投稿2018/11/16 08:19

tacsheaven

総合スコア13703

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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 "おわりました。"

投稿2018/11/16 08:07

takasima20

総合スコア7458

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

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

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

VBA

1Sub getBuso() 2 Application.ScreenUpdating = False 34 Application.ScreenUpdating = True 5End Sub

投稿2018/11/16 07:29

編集2018/11/16 07:29
ttyp03

総合スコア16998

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sumire_cl

2018/11/16 13:12

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

2018/11/16 13:18

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

2018/11/16 15:21

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

0

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

投稿2018/11/16 07:23

trick

総合スコア366

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問