[[20180104162500]] 『txtファイルから特定文字列に挟まれた行情報全』(老眼です) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『txtファイルから特定文字列に挟まれた行情報全部を別シートに保存したい』(老眼です)

テキストファイルに保存してある文字行の中から、特定の文字行に挟まれた行を選択し、Excel2010でマクロを使って、Excelに貼り付けたいです。
例えば、

<テキストファイル例>
※例なので実際のテキスト内容は下記に限らず。

 東京	A	B			
 大阪		B			
 名古屋	A				
 神戸			C	D	
 広島				D	E
 福岡		B			
 鹿児島 					E

 北海道		B			
 東京	A				
 大阪	A				
 名古屋				D	
 広島		B			
 福岡			C		
 鹿児島 				D	

 北海道		B			
 山形	A	B			
 大阪			C	D	E
 広島					
 福岡	A				
 宮崎				D	E

 青森	A	B			
 東京		B	C		
 大阪			C	D	
 京都					
 岡山	A				
 福岡		B			
 那覇				D	

<上記の内、コピーしたい行>

 ※大阪から福岡までの行情報全部を選択したいです。
 大阪	A				
 名古屋				D	
 広島		B			
 福岡			C		

 大阪	A			
 名古屋				D
 広島		B		
 福岡			C	

 大阪			C	D	E
 広島					
 福岡	A				

 大阪			C	D
 京都				
 岡山	A			
 福岡		B		

ですが実際は、txtデータをExcelにはり付けるところまでは動くのですが、そのあと

大阪
名古屋
広島
福岡

…のように最初の1セット目の項目までを抽出したところで終わってしまいます。どこをどう変更すればよいか、お知恵をお貸しください。

(以下全文)

Sub PasteFromCSV()

    Const CSV_FILE = "C:\Users\user\Documents\test.txt"
    Dim ReadWBk As Workbook
    Dim WriteWBk As Workbook
    Dim WriteSht As Worksheet
    Dim Rng As Range

    Set WriteWBk = ActiveWorkbook
    Set WriteSht = WriteWBk.ActiveSheet

    Set ReadWBk = Workbooks.Open(CSV_FILE)
    'Set Rng = ReadWBk.Worksheets.Item(1).UsedRange
    'Range("A1:A1700").Copy

    Dim startStr As String
    Dim endStr As String
    Dim copyFlag As Boolean
    Dim writeRow As Long

    startStr = "大阪"
    endStr = "福岡"
    copyFlag = False
    writeRow = 1

    For Each c In ReadWBk.Worksheets(1).Range("A1:A" & Range("A1").End(xlDown).Row)
        If c = startStr Then copyFlag = True
        If copyFlag Then
            WriteSht.Cells(writeRow, 1) = c
            writeRow = writeRow + 1
            If c = endStr Then Exit For
        End If
    Next

End Sub

< 使用 Excel:Excel2010、使用 OS:unknown >


>1セット目の項目までを抽出したところで終わってしまいます

> If c = endStr Then Exit For

ループを抜けずに継続したいということでしょうか?
もっと、簡潔に記述できそうなきもしますが
きっと、こんな感じで、

        If c = startStr Then
            copyFlag = True
        ElseIf c = endStr Then
            copyFlag = False
            WriteSht.Cells(writeRow, 1) = c
            writeRow = writeRow + 1
        End If
        If copyFlag Then
            WriteSht.Cells(writeRow, 1) = c
            writeRow = writeRow + 1
        End If

(マナ) 2018/01/04(木) 21:12


こっちのほうが、元コードに近いのでわかりやすかったですね

       If c = startStr Then copyFlag = True
        If copyFlag Then
            WriteSht.Cells(writeRow, 1) = c
            writeRow = writeRow + 1
        End If     
        If c = endStr Then copyFlag = False

(マナ) 2018/01/04(木) 21:58


 老眼ですさん、

 全くの別案です、
 元のテキストファイルを加工して同フォルダにtest_大阪_福岡.txtを新たに作成します。
 それを読み込むだけにする

 Sub test()
     Dim fn As String, txt As String, a() As String, i As Long
     fn = Application.GetOpenFilename("テキストファイル,*.txt")
     If fn = "False" Then Exit Sub
     txt = CreateObject("Scripting.FileSystemObject").OpenTextFile(fn).ReadAll
     With CreateObject("VBScript.RegExp")
         .Global = True: .MultiLine = True
         .Pattern = "大阪(.*[\r\n]+.)+?(福岡).*"
         ReDim a(1 To .Execute(txt).Count)
         For i = 0 To .Execute(txt).Count - 1
             a(i + 1) = .Execute(txt)(i)
         Next
     End With
     Open Replace(fn, ".txt", "_大阪_福岡.txt") For Output As #1
         Print #1, Join(a, String(2, vbCrLf))
     Close #1
     Workbooks.OpenText (Replace(fn, ".txt", "_大阪_福岡.txt"))
 End Sub
(seiya) 2018/01/04(木) 22:02

マナさん、seiyaさん、早速のアドバイス、ありがとうございます。

>マナさん
あ!そうです。ありがとうございます。動作後のイメージはこんな感じです。
可能ならば、B列以降のデータ(A、B、Cなどの…)も落とさずにペーストできるとよいのですが、どのように記述するのが良いでしょうか?例ですと、F列までしかデータは入っていませんが、実際はI列くらいまでデータが入ることもあり、汎用性のあるコードを書ければよいのですが、私では全然力不足でして…。質問ばかりですみませんが、良い案ありましたらお願いします。

>seiyaさん
すごいです。こんな短時間で別案を考えて下さったのですね。ありがとうございます。
試してみたのですが、オーバーフロー?なのか途中でExcelが動かなくなってしまいました><

>元のテキストファイルを加工
とは具体的にどうすべきでしょうか?
もしかしてここで引っかかっているのかなという気もするのですが。
お手数おかけしてすみません。よかったらお願いします。
(老眼です) 2018/01/05(金) 11:17


 おそらくデータ量が想定していたものとは比べ物にならない程大量なのでしょうね。

 此方で試してください。

 Sub test()
     Dim fn As String, txt As String, a() As String, n As Long, mtch As Object, m As Object
     fn = Application.GetOpenFilename("テキストファイル,*.txt")
     If fn = "False" Then Exit Sub
     txt = CreateObject("Scripting.FileSystemObject").OpenTextFile(fn).ReadAll
     With CreateObject("VBScript.RegExp")
         .Global = True: .MultiLine = True
         .Pattern = "大阪(.*[\r\n]+.)+?(福岡).*"
         Set mtch = .Execute(txt)
         ReDim a(1 To mtch.Count)
         For Each m In mtch
            n = n + 1: a(n) = m.Value
         Next
     End With
     Open Replace(fn, ".txt", "_大阪_福岡.txt") For Output As #1
         Print #1, Join(a, String(2, vbCrLf))
     Close #1
     Workbooks.OpenText (Replace(fn, ".txt", "_大阪_福岡.txt"))
 End Sub
( seiya) 2018/01/05(金) 12:24

既に、マナさんやseiyaさんの回答で満足されておられるかもしれませんが、ちょっとおもしろそうなテーマだったので、私も考えてみました。

前提条件
・プロシージャ名、変数名から推測して読み込むテキストファイルは「CSV形式」
・「大阪」で始まる行から「福岡」で始まる行までは、シートに取り込むが、「福岡」で始まる行の次の行から、
 「大阪」で始まる行の前の行はシートに取り込む必要がない。
・「大阪」と「福岡」の順は逆転しない。(「福岡」から「大阪」でサンドイッチされているものは対象外。)

主な処理フロー
(1)OPENステートメントでテキストファイルを開いて1行ずつ読込
(2)読込行は変数「buf」に格納
(3)「buf」が「大阪」で始まっていたら「フラグ」をTreuに変更
(4)「フラグ」がTureなら、「buf」をシートに出力
(5)「buf」が「大阪」で始まっていたら「フラグ」をFalseに変更
(6)次の行を読み込む
(7)(2)から(6)をテキストファイルの最終行までループ

コードにしてみるとこんな感じになりました。
Sub Sample()
'==変数の宣言とか
Const CSV_FILE = "C:\Users\user\Documents\test.txt"
Dim WS As Worksheet

    Set WS = ThisWorkbook.Worksheets(1)
Dim buf As String
Dim 出力行 As Long
    出力行 = 1
Dim フラグ As Boolean
    フラグ = False 'Boolean型の初期値がFALSEなので省略可

'==主処理
Open CSV_FILE For Input As #1

    Do Until EOF(1)
        Line Input #1, buf
        If buf Like "大阪*" Then フラグ = True
        If フラグ = True Then
            WS.Cells(出力行, "A").Resize(, UBound(Split(buf, ",")) + 1).Value = _
                Split(buf, ",")
            出力行 = 出力行 + 1
        End If
        If buf Like "福岡*" Then フラグ = False
    Loop
Close #1

'==後処理(オブジェクト解放)
Set WS = Nothing

End Sub
(もこな2) 2018/01/05(金) 12:46


seiyaさん、もこな2さん、ありがとうございます。こんなに早く返答頂けて驚いてます。

>seiyaさん
度々ありがとうございます。

情報量を1000行程度に減らしたうえで2度目に頂いたコードも試したのですが、やはり途中で止まってしまいました。せっかく書いて頂けたので何とか動かしてみたいのですが…。何かデータ側に適合しない点がないか少し考えてみます。

>もこな2さん
動作、完璧でした。しかも、処理フロー、コード解説まで丁寧にしてくださって大変助かります。
一つ伺ってみたいのですが、地名をA列に、アルファベット集合をB列にペーストするのは難しいでしょうか?(この形に持っていけると、その後の作業性が格段に上がるのです)
お時間あれば…でよいです。よろしくお願いします。

(老眼です) 2018/01/05(金) 14:30


 >情報量を1000行程度に減らしたうえで2度目に頂いたコードも試したのですが、やはり途中で止まってしまいました。

 変ですねーー。

 此方では 60000行超で試しています。
 抽出行は 55000行超ですが、ファイル選択後2秒そこそこで完了します。
( seiya) 2018/01/05(金) 14:37

う〜ん。CSVファイルのレイアウトがどうなってるかわからないのでうまくいくかわからないですけど、とりあえずこんな感じではどうでしょうか。
A列は配列の0番目をそのまま出力するとして、
B列にはJOIN関数で配列の中身を「・」挟みながらくっつけたものを、Replace関数で 配列の0番目(A列の内容)&「・」をブランクと置換(=削除)して出力。
If フラグ = True Then
 WS.Cells(出力行, "A").Value = Split(buf, ",")(0)
  WS.Cells(出力行, "B").Value = Replace(Join(Split(buf, ","), "・"), Split(buf, ",")(0) & "・", "")
  出力行 = 出力行 + 1
End If

ブランク値はくっつけないとかだと、ちょっと難易度あがりますが、整数型とString型の変数(たとえば「i、tmp」など)を用意(宣言)して
If フラグ = True Then

    WS.Cells(出力行, "A").Value = Split(buf, ",")(0)
    tmp = ""
    For i = 1 To UBound(Split(buf, ","))
        If Split(buf, ",")(i) <> "" Then tmp = tmp & Split(buf, ",")(i) & "・"
    Next i
    If Len(tmp) > 0 Then WS.Cells(出力行, "B").Value = Left(tmp, Len(tmp) - 1)
    出力行 = 出力行 + 1
End If
こんな感じでしょうか。(ごちゃごちゃしちゃってますが・・・)
(もこな2) 2018/01/05(金) 15:29

seiyaさんのコードに興味があったので、ステップ実行してみたところ
Set mtch
でちょっと時間がかかったあと、
ReDimのところでコケました。

ローカルウィンドウでみると。
mtchの下位に[NewEnum]ってあって <サポートされていないオブジェクト型> って出てるので、なんか参照設定が必要なのかも?(私のスキルではこれ以上解らないです。。)
(もこな2) 2018/01/05(金) 15:45


 一応実行データをアップしておきます。
 データが元々違っていれば、エラーもありうるでしょう。

http://firestorage.jp/download/f9ac16db556632fcc57a4cceccbb113e0d68db34
ダウンロードパスワード mebw77in
(seiya) 2018/01/05(金) 16:04


Sub main()
    Dim x As String, f As String, a As String, b As String, buf As String, i As Long, j As Long, k As Long
    Cells.ClearContents
    x = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    f = "C:\Users\user\Documents\test.txt"
    Open f For Input As #1
        Do Until EOF(1)
            Line Input #1, buf
            If InStr(buf, "大阪") > 0 Then flg = True
                 If flg Then
                        a = buf
                        b = ""
                        For i = 1 To Len(buf)
                            For j = 1 To Len(x)
                                If Mid(buf, i, 1) = Mid(x, j, 1) Then
                                    a = Replace(a, Mid(buf, i, 1), "")
                                    b = b & Mid(x, j, 1)
                                    Exit For
                                End If
                            Next j
                        Next i
                        k = k + 1
                        Cells(k, 1).Resize(, 2).Value = Array(a, b)
                End If
            If InStr(buf, "福岡") > 0 Then flg = False
        Loop
    Close #1
End Sub
(mm) 2018/01/05(金) 16:45

seiyaさん、もこな2さん、?oさん みなさんありがとうございます!

>seiyaさん
実行データ、ありがとうございました。どうやら地名の前の半角スペースの有無が原因だったようです。
完全にこちらの説明不足です。すみません。ここで例を示す際に最初に半角スペースを入れないとtxtデータと同じように表記できなかったのであえてそうしたのですが、実際のデータはスペースが入ってないものでした(汗)
こちらのデータにも同じように半角スペースを入れてみると、動きました。

動作結果はもともとこちらがイメージしていたそのままを再現していただけました。本当にありがとうございます!

>もこな2さん
2パターンも考えていただいたき、ありがとうございます。
試してみましたが、1つ目のパターンですとA列にもB列にも地名+アルファベット集合がペーストされ、2つ目はA列に地名+アルファベット集合がペーストされました。
もこな2さんのおっしゃるようにファイルのレイアウトが違うのかもしれません。
うまく説明できず申し訳ありません。

>mmさん
ありがとうございます。この形までもっていけるんですね…。すごいです。
これがあれば、相当に作業効率が良くなるので助かります。

しかし、皆さん本当にすごいです。アプローチの仕方も様々で、勉強になります。
何時間何日かけてもエラーばかりのコードしか書けない老眼…、時々嫌になりますが、ちまちまと頑張ります。また、わからないことがあれば質問させてください。

(老眼です) 2018/01/05(金) 19:58


 スペースが無くても動くと思うのですが?

 とりあえず、こんな形でA/B列が抽出されます。

 Sub test()
     Dim fn As String, txt As String, a() As String, n As Long, mtch As Object, m As Object, s As Object
     fn = Application.GetOpenFilename("テキストファイル,*.txt")
     If fn = "False" Then Exit Sub
     txt = CreateObject("Scripting.FileSystemObject").OpenTextFile(fn).ReadAll
     With CreateObject("VBScript.RegExp")
         .Global = True: .MultiLine = True
         .Pattern = ""
         .Pattern = "^大阪(.*[\r\n])+?(福岡).*"
         Set mtch = .Execute(txt)
         ReDim a(1 To mtch.Count)
         .Pattern = "^(.+?\t)(.*)"
         For Each m In mtch
            n = n + 1
            For Each s In .Execute(m.Value)
                a(n) = a(n) & s.submatches(0) & Replace(s.submatches(1), vbTab, "")
            Next
         Next
     End With
     Open Replace(fn, ".txt", "_大阪_福岡.txt") For Output As #1
         Print #1, Join(a, String(2, vbCrLf))
     Close #1
     Workbooks.OpenText (Replace(fn, ".txt", "_大阪_福岡.txt"))
 End Sub
(seiya) 2018/01/05(金) 20:25

seiyaさん 

すみません、スペースの有無でないとすると原因がよくわからないのです。スペース以外にデータパターンに違いがないように思え、入れてみると動くのでてっきりこれかと…。

先ほど新たに提示いただいたコードですが、”インデックスが有効範囲にありません”とのエラーで実行できませんでした。データは上記で試させて頂いたのと同じものなのですが…。
(老眼です) 2018/01/05(金) 22:11


 最後のコードは文頭にスペースが無いものとしてアップしています。
 ですので、マッチする文字列が抽出されないので
 >”インデックスが有効範囲にありません”
 のエラーが出ます。

 両方のデータでマッチさせるには、Patternを

          .Pattern = "^ *大阪(.*[\r\n])+?( *福岡).*"

 に差し替えてください。

(seiya) 2018/01/05(金) 22:35


seiyaさん、ありがとうございます。

何と。もうそこまで考えて頂いていたのですね。
おかげさまでコード実行できました。結果もとてもきれいな形で出力され、思い描いたとおりに作業を進められそうです。
長らくの悩みがようやく解決し、助かりました!

(老眼です) 2018/01/06(土) 10:08


コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.