Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


2376 / 13645 ツリー ←次へ | 前へ→

【67107】テキストデータから数値をもってきて表を作りたい くま 10/11/4(木) 16:00 質問[未読]
【67108】Re:テキストデータから数値をもってきて表... kanabun 10/11/4(木) 16:39 発言[未読]
【67109】Re:テキストデータから数値をもってきて表... kanabun 10/11/4(木) 16:56 発言[未読]
【67110】Re:テキストデータから数値をもってきて表... kanabun 10/11/4(木) 17:24 発言[未読]
【67115】Re:テキストデータから数値をもってきて表... くま 10/11/5(金) 9:42 質問[未読]
【67116】Re:テキストデータから数値をもってきて表... kanabun 10/11/5(金) 10:51 発言[未読]
【67117】Re:テキストデータから数値をもってきて表... kanabun 10/11/5(金) 11:04 発言[未読]
【68394】Re:テキストデータから数値をもってきて表... くま 11/3/2(水) 16:56 質問[未読]
【68397】Re:テキストデータから数値をもってきて表... kanabun 11/3/2(水) 20:44 発言[未読]
【68398】Re:テキストデータから数値をもってきて表... kanabun 11/3/2(水) 20:47 回答[未読]
【68399】Re:テキストデータから数値をもってきて表... kanabun 11/3/2(水) 21:12 発言[未読]
【68401】Re:テキストデータから数値をもってきて表... kanabun 11/3/2(水) 21:30 回答[未読]
【67118】Re:テキストデータから数値をもってきて表... Yuki 10/11/5(金) 11:54 発言[未読]

【67107】テキストデータから数値をもってきて表を...
質問  くま E-MAIL  - 10/11/4(木) 16:00 -

引用なし
パスワード
   VBA初心者です。
■下ような英文と!の羅列したテキストのデータがあります。
interface FastEthernet0/1
shutdown
!
hostname ABC
!
vlan internal allocation policy ascending
vlan access-log ratelimit 2000
!
vlan 220-221,306
vlan 2105-2107,3100-3103
!
snmp-server
!

▼したいこと
(1)フォルダ内のファイル(拡張子は.log)を開く
 ※エクセルで開くか、そのまま.logファイルとして開く
 ※ファイルは数百個あります。
(2)一行目から順に読んで行き、「vlan 数字」という行をみつけたら数字だけを取り出して新しいブックに記入。
 ただし、「-」は数字の連番を表しており、間に入る数の分だけ空白セルを入れたい
 例:220-221なら220,221(空白セル無し)
   3100-3103なら3100,  ,  ,3103(空白セル2つ)
 ※できれば3101,3102など間の数字を自動入力したい(出来なければ後から手入力します)連番数はファイルによって異なります。
 ※区切り文字でセルを分ける、横一列を縦一列に入れ替える作業はマクロの記録で出来ました。
 ※!や他の英文は読み飛ばします
(3)「hostname ABC」の"ABC"部分だけ取得し、C列を参照して、C列の行数分B列に入力
(4)現在のINPUTファイルを閉じて、次のファイルを開く。以下(1)〜(4)の作業を繰り返し、フォルダ内全てのファイルを処理します。
 ※すべてのファイルで異なるのは「hostname 」後のABC部分(本来は10文字前後)と、「vlan 」あとの始まる数字(1〜9のどれか)、数字の数です。

OUTPUTブックは同じブックで、最終的に下記のような形で表を作りたいのですが、コードを教えていただけないでしょうか。

     A     B     C     D
1        ホスト名  vlan ID
2          ABC    220
3          ABC    221
4          ABC    306
5          ABC    2105
6          ABC    2106
7          ABC    2107
8          ABC    3100
9           ABC    3101
10         ABC    3102
11         ABC    3103
12         DEF    101
13         DEF    206
14         GHI    1100
15         GHI    1101
16         GHI    1102


お分かりになる方がいらっしゃいましたら、お願いいたします。

【67108】Re:テキストデータから数値をもってきて...
発言  kanabun  - 10/11/4(木) 16:39 -

引用なし
パスワード
   ▼くま さん:こんにちは〜

おもしろそうな問題ですね〜
アイデアだけですが、
正規表現を使って抽出したらどうでしょう?
'Microsoft VBScript Regular Expressions 5.5 への参照設定

以下はLogファイルを開いて、本文中から
とにかく【数値またはハイフン】が連続する部分を
イミディエイト・ウィンドウに吐き出しています。

Sub Try1()
 Dim io As Integer
 Dim myLogFile As String: myLogFile = "E:\(Data)\temp8Log\hoge.log"
 Dim buf() As Byte
 Dim sss As String
 Dim rex As RegExp
 Dim mm As Match
 Set rex = New RegExp
 
 io = FreeFile()
 Open myLogFile For Binary As io
  ReDim buf(1 To LOF(io))
  Get io, , buf
 Close io
 sss = StrConv(buf, vbUnicode)
 
 With rex
   .Pattern = "[\d-]+" '【数値またはハイフン】が連続する部分
   .Global = True
   .MultiLine = True
   For Each mm In .Execute(sss)
     Debug.Print mm.Value
   Next
 End With
End Sub

【67109】Re:テキストデータから数値をもってきて...
発言  kanabun  - 10/11/4(木) 16:56 -

引用なし
パスワード
   ▼くま さん:

>(2)「vlan 数字」という行をみつけたら数字だけを取り出し

>(3)「hostname ABC」の"ABC"部分だけ取得

Try1()に上の要件を追加してみました

Sub Try2()
 Dim io As Integer
 Dim myLogFile As String: myLogFile = "E:\(Data)\temp8Log\hoge.log"
 Dim buf() As Byte
 Dim ss() As String
 Dim hostname As String, ok As Boolean
 Dim i As Long
 Dim rex As RegExp
 Dim mm As Match
 Set rex = New RegExp
 
 io = FreeFile()
 Open myLogFile For Binary As io
  ReDim buf(1 To LOF(io))
  Get io, , buf
 Close io
 ss = Split(StrConv(buf, vbUnicode), vbCrLf)
 
 With rex
   .Pattern = "[\d-]+"
   .Global = True
   For i = 0 To UBound(ss) - 1
    If Not ok Then
      If ss(i) Like "hostname*" Then
        hostname = Split(ss(i))(1)
        Debug.Print "hostname", hostname
        ok = True
      End If
    ElseIf ss(i) Like "vlan*" Then
     For Each mm In .Execute(ss(i))
       If mm.Value <> "-" Then Debug.Print mm.Value
     Next
    End If
   Next
 End With
End Sub

【67110】Re:テキストデータから数値をもってきて...
発言  kanabun  - 10/11/4(木) 17:24 -

引用なし
パスワード
   ↑Try2()を提示のLogファイルサンプルに対して実行すると、
イミディエイト・ウィンドウには
----------------------
hostname   ABC
2000
220-221
306
2105-2107
3100-3103
----------------------

と表示されると思います。

↓を走らせると、
Sub Try3()
 Dim io As Integer
 Dim myLogFile As String: myLogFile = "E:\(Data)\temp8Log\hoge.log"
 Dim buf() As Byte
 Dim ss() As String, s As String, Series, num As Long
 Dim hostname As String, ok As Boolean
 Dim i As Long, j As Long
 Dim rex As RegExp
 Dim mm As Match
 Set rex = New RegExp
 
 io = FreeFile()
 Open myLogFile For Binary As io
  ReDim buf(1 To LOF(io))
  Get io, , buf
 Close io
 ss = Split(StrConv(buf, vbUnicode), vbCrLf)
 
 With rex
   .Pattern = "[\d-]+"
   .Global = True
   For i = 0 To UBound(ss) - 1
    If Not ok Then
      If ss(i) Like "hostname*" Then
        hostname = Split(ss(i))(1)
        Debug.Print "hostname", hostname
        ok = True
      End If
    ElseIf ss(i) Like "vlan*" Then
     For Each mm In .Execute(ss(i))
       s = mm.Value
       If s <> "-" Then
         Series = Split(s, "-")
         num = Series(0)
         For j = num To Val(Series(UBound(Series)))
           Debug.Print j;
         Next
         Debug.Print
       End If
     Next
    End If
   Next
 End With
End Sub

こんどはイミディエイト・ウィンドウに
----------------------
hostname   ABC
2000
220 221
306
2105 2106 2107
3100 3101 3102 3103
----------------------
と表示されると思います。

#こんな風に、すこしづつ仕様に近づけていってください。

【67115】Re:テキストデータから数値をもってきて...
質問  くま E-MAIL  - 10/11/5(金) 9:42 -

引用なし
パスワード
   ▼kanabun さん:

すみません、一点付け足したいのですが、

>vlan access-log ratelimit 2000
の2000は取得しない処理にしたいのです、、、

できますでしょうか?

【67116】Re:テキストデータから数値をもってきて...
発言  kanabun  - 10/11/5(金) 10:51 -

引用なし
パスワード
   ▼くま さん:

>>vlan access-log ratelimit 2000
>の2000は取得しない処理にしたいのです、、、


【取得しない例】
> vlan access-log ratelimit 2000

【取得する例】
> vlan 220-221,306
> vlan 2105-2107,3100-3103

このちがいはなんでしょうか?
規則がありそうですが?

【67117】Re:テキストデータから数値をもってきて...
発言  kanabun  - 10/11/5(金) 11:04 -

引用なし
パスワード
   > vlan access-log ratelimit 2000
> vlan 220-221,306
> vlan 2105-2107,3100-3103
   ↑もし「vlan 」のあとの1文字が数字だったら【取得】
   a のように数字でなかったら【スキップ】
ということであれば、
------------------------------
Sub Try4()
 Dim io As Integer
 Dim myLogFile As String: myLogFile = "E:\(Data)\temp8Log\hoge.log"
 Dim buf() As Byte
 Dim ss() As String, s As String, Series, num As Long
 Dim hostname As String, ok As Boolean
 Dim i As Long, j As Long
 Dim rex As RegExp
 Dim mm As Match
 Set rex = New RegExp
 
 io = FreeFile()
 Open myLogFile For Binary As io
  ReDim buf(1 To LOF(io))
  Get io, , buf
 Close io
 ss = Split(StrConv(buf, vbUnicode), vbCrLf)
 
 With rex
   .Pattern = "[\d-]+"
   .Global = True
   For i = 0 To UBound(ss) - 1
    If Not ok Then
      If ss(i) Like "hostname*" Then
        hostname = Split(ss(i))(1)
        Debug.Print , "hostname", "vlan ID"
        ok = True
      End If
    ElseIf ss(i) Like "vlan*" Then
      If Mid$(ss(i), 6, 1) Like "#" Then '◆条件追加
       For Each mm In .Execute(ss(i))
         s = mm.Value
         If s <> "-" Then
           Series = Split(s, "-")
           num = Series(0)
           For j = num To Val(Series(UBound(Series)))
             Debug.Print , hostname, j
           Next
         End If
       Next
      End If
    End If
   Next
 End With
End Sub

#Try4()実行結果
-------------------------------------
       hostname   vlan ID
       ABC      220
       ABC      221
       ABC      306
       ABC      2105
       ABC      2106
       ABC      2107
       ABC      3100
       ABC      3101
       ABC      3102
       ABC      3103

【67118】Re:テキストデータから数値をもってきて...
発言  Yuki  - 10/11/5(金) 11:54 -

引用なし
パスワード
   ▼くま さん:
配列処理で
Sub Testa()
  Dim io   As Integer
  Dim strFnm As String
  Dim buf()  As Byte
  Dim i    As Long
  Dim j    As Long
  Dim k    As Long
  Dim x    As Long
  Dim y    As Long
  Dim z    As Long
  Dim d    As Variant
  Dim r    As Variant
  Dim v    As Variant
  Dim v1   As Variant
  Dim v2   As Variant
  Dim hd   As Variant
  
  strFnm = "D:\excel\test9\test.log"
  If Dir(strFnm) = "" Then Exit Sub
  hd = Array("hostname", "vlan ID")
  Cells.ClearContents
  Range("A1").Resize(1, 2).Value = hd
  
  io = FreeFile()
  Open strFnm For Binary As io
   ReDim buf(1 To LOF(io))
   Get io, , buf
  Close io
  
  v = Split(StrConv(buf, vbUnicode), "hostname")
  For i = 1 To UBound(v)
    d = Split(v(i), vbCrLf)
    ReDim r(UBound(d), 1)
    k = -1
    For j = 0 To UBound(d)
      On Error Resume Next
      If Val(Split(d(j), "vlan ")(1)) Then
        If Err.Number = 0 Then
          v1 = Split(Split(d(j), "vlan ")(1), ",")
          For x = 0 To UBound(v1)
            v2 = Split(v1(x), "-")
            If UBound(v2) > 0 Then
              For z = v2(0) To v2(1)
                k = k + 1
                r(k, 0) = Trim(d(0))
                r(k, 1) = z
              Next
            Else
              k = k + 1
              r(k, 0) = Trim(d(0))
              r(k, 1) = Val(v1(x))
            End If
          Next
        End If
      End If
      On Error GoTo 0
    Next
    Cells(Range("A" & Rows.Count).End(xlUp).Row + 1, 1).Resize(k + 1, 2).Value = r
  Next
End Sub

【68394】Re:テキストデータから数値をもってきて...
質問  くま  - 11/3/2(水) 16:56 -

引用なし
パスワード
   kanabunさん
昨年はいろいろとご教示いただきましてありがとうございます。

前回の質問で頂いた回答から、自分なりに変更してみたのですが上手くいかないので、再度ご教示いただければと思います。

-------------------------------------------------

フォルダ内のファイルを順に処理するループ処理に変えてみたのですが、
vlan値は正常に取ってくるのですが、
hostnameの値が一番最初に見たファイルの値のままなのです。

roopと書く場所が間違っているのでしょうか…?

  hostname   vlan ID
   ABC      220
   ABC      221
   ABC      306 
   ABC      3100
   ABC      3101
   ABC      3102
   ABC      3103
   ABC      110  ←ここから次のファイル(別のhostnameになる)
   ABC      306
   ABC      1900
   ABC      2105
   ABC      2106

-------------------------------------------------
Sub Try_test()
Dim io As Integer
Dim myLogFile As String
Dim buf() As Byte
Dim ss() As String, s As String, Series, num As Long
Dim hostname As String, ok As Boolean
Dim i As Long, j As Long
Dim rex As RegExp
Dim mm As Match
Set rex = New RegExp

ChDir ("C:\マクロ")
myLogFile = Dir("*.log", vbNormal)

Do While myLogFile <> ""

io = FreeFile()
Open myLogFile For Binary As io
    ReDim buf(1 To LOF(io))
    Get io, , buf
Close io
ss = Split(StrConv(buf, vbUnicode), vbCrLf)

With rex
    .Pattern = "[\d-]+"
    .Global = True
    For i = 0 To UBound(ss) - 1
        If Not ok Then
            If ss(i) Like "hostname*" Then
                hostname = Split(ss(i))(1)
                Debug.Print , "hostname", "vlan ID"
                ok = True
            End If
        ElseIf ss(i) Like "vlan*" Then
            If Mid$(ss(i), 6, 1) Like "#" Then
            For Each mm In .Execute(ss(i))
                s = mm.Value
                If s <> "-" Then
                    Series = Split(s, "-")
                    num = Series(0)
                    For j = num To Val(Series(UBound(Series)))
                        Debug.Print , hostname, j
                    Next
                End If
            Next
            End If
        End If
    Next
    
End With
    myLogFile = Dir()
Loop

End Sub

【68397】Re:テキストデータから数値をもってきて...
発言  kanabun  - 11/3/2(水) 20:44 -

引用なし
パスワード
   ▼くま さん:
>kanabunさん
>昨年はいろいろとご教示いただきましてありがとうございます。
くま さん、お久ですね(^^

>自分なりに変更してみたのですが
>フォルダ内のファイルを順に処理するループ処理に変えてみたのですが、
>vlan値は正常に取ってくるのですが、
>hostnameの値が一番最初に見たファイルの値のままなのです。

問題のか所は
>    For i = 0 To UBound(ss) - 1
>     If Not ok Then
>       If ss(i) Like "hostname*" Then
>         hostname = Split(ss(i))(1)
>         Debug.Print , "hostname", "vlan ID"
>         ok = True
のところにあります。
この変数ok は まだhostnameが見つかっていないときには
"vlan*" の行の解析をしないフラッグ(目印)です。
hostname がみつかったときはじめて ok = True にしています。

それが複数ファイルのとき、一番最初のファイルのhostnameが
読み込まれて ok=True になったあと、
次のファイルに移るときは いったん ok=False に戻しておかないと
2番目からのファイルは ok=True なので そのファイルのhostname を
読む処理をスキップしてしまいます。
で、最初のファイルのhostname がずっと現れているわけです。
ファイル読み込みが終了したら ◆のところに ok=False を追加してください。

ちょっとインデントが深く、読みにくかったので、
順番を入れ替えるついでに編集しました。

Sub Try4_JoinFile()
  Const myPath = "D:\(Data)\temp8log" '"C:\マクロ"
  Dim io As Integer
  Dim myLogFile As String
  Dim buf() As Byte
  Dim ss() As String, s As String, Series, num As Long
  Dim hostname As String, ok As Boolean
  Dim i As Long, j As Long
  Dim rex As RegExp
  Dim mm As Match
  Set rex = New RegExp
  rex.Pattern = "[\d-]+"
  rex.Global = True
  
  ChDrive myPath
  ChDir myPath
  myLogFile = Dir("*.log", vbNormal)
  
  Do While Len(myLogFile) > 0
    '------------ ファイルを読み込む
    io = FreeFile()
    Open myLogFile For Binary As io
     ReDim buf(1 To LOF(io))
     Get io, , buf
    Close io
    ss = Split(StrConv(buf, vbUnicode), vbCrLf)
 
    '------------  抽出
    For i = 0 To UBound(ss) - 1
     If Not ok Then
       If ss(i) Like "hostname*" Then
         hostname = Split(ss(i))(1)
         Debug.Print , "hostname", "vlan ID"
         ok = True
       End If
     ElseIf ss(i) Like "vlan*" Then
       If Mid$(ss(i), 6, 1) Like "#" Then
        For Each mm In rex.Execute(ss(i))
          s = mm.Value
          If s <> "-" Then
            Series = Split(s, "-")
            num = Series(0)
            For j = num To Val(Series(UBound(Series)))
              Debug.Print , hostname, j
            Next
          End If
        Next
       End If
     End If
    Next
    ok = False  '◆ファイル読みが終了したら ok = False に戻す
    '-------------- 次のログファイル
    myLogFile = Dir$()
  Loop
End Sub

【68398】Re:テキストデータから数値をもってきて...
回答  kanabun  - 11/3/2(水) 20:47 -

引用なし
パスワード
   失礼 コードの宣言部
> Const myPath = "D:\(Data)\temp8log" '"C:\マクロ"

こちらの環境のままでした。

Const myPath = "C:\マクロ"

に直してお試しください。

【68399】Re:テキストデータから数値をもってきて...
発言  kanabun  - 11/3/2(水) 21:12 -

引用なし
パスワード
   さきほどのコード 出力先を(イミディエイト・ウィンドウから)
シート(ActiveSheet)に変更してみました。
他は変更なしです。

Sub Try4_MultiFile()
  Const myPath = "C:\マクロ"
  Dim io As Integer
  Dim myLogFile As String
  Dim buf() As Byte
  Dim ss() As String, s As String, Series, num As Long
  Dim hostname As String, ok As Boolean
  Dim i As Long, j As Long
  Dim vout() As String
  Dim L As Long, Lmax As Long: Lmax = 500
  ReDim vout(1 To 2, Lmax)
  vout(1, 0) = "hostname": vout(2, 0) = "vlan ID"
  
  Dim rex As RegExp
  Dim mm As Match
  Set rex = New RegExp
  rex.Pattern = "[\d-]+"
  rex.Global = True
  
  ChDrive myPath
  ChDir myPath
  myLogFile = Dir("*.log", vbNormal)
  
  Do While Len(myLogFile) > 0
    '------------ ファイルを読み込む
    io = FreeFile()
    Open myLogFile For Binary As io
     ReDim buf(1 To LOF(io))
     Get io, , buf
    Close io
    ss = Split(StrConv(buf, vbUnicode), vbCrLf)
 
    '------------  抽出
    For i = 0 To UBound(ss) - 1
     If Not ok Then
       If ss(i) Like "hostname*" Then
         hostname = Split(ss(i))(1)
         ok = True
       End If
     ElseIf ss(i) Like "vlan*" Then
       If Mid$(ss(i), 6, 1) Like "#" Then
        For Each mm In rex.Execute(ss(i))
          s = mm.Value
          If s <> "-" Then
            Series = Split(s, "-")
            num = Series(0)
            For j = num To Val(Series(UBound(Series)))
              L = L + 1
              If L > Lmax Then
                Lmax = Lmax + 500
                ReDim Preserve vout(1 To 2, Lmax)
              End If
              vout(1, L) = hostname
              vout(2, L) = j
            Next
          End If
        Next
       End If
     End If
    Next
    ok = False  '◆ファイル読みが終了したらok=Falseに戻す
    '-------------- 次のログファイル
    myLogFile = Dir$()
  Loop
  
  '-------------------- シートに書き出す
  If L > 0 Then
    With ActiveSheet
      .UsedRange.ClearContents
      .Range("A1").Resize(L, 2).Value = _
       Application.Transpose(vout)
    End With
    Beep
  End If
End Sub

【68401】Re:テキストデータから数値をもってきて...
回答  kanabun  - 11/3/2(水) 21:30 -

引用なし
パスワード
   直前のコード、まちがいを発見

>  .Range("A1").Resize(L, 2).Value = _
       Application.Transpose(vout)

  ↓ 以下に変更ねがいます

  .Range("A1").Resize(L + 1, 2).Value = _
       Application.Transpose(vout)

2376 / 13645 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free