[[20130119094926]] 『テキストファイルの全行の最大タブ区切り数を取得』(カシスソーダ) ページの最後に飛ぶ

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

 

『テキストファイルの全行の最大タブ区切り数を取得』(カシスソーダ)

 こんにちは、よろしくお願いいたします。
 ダイアログなどで指定したテキストファイルの内容をリストボックスに
 取り込むコードの効率化を考えています。

 現状では、
 1 一度テキストファイルの内容を取得し変数に格納

 2 変数に格納したテキストファイルの内容をVbCrlfでSplitし行数(Uboundを変数RowNumに格納)を取得

 3  Splitした各行をループし各行をTabでSplitしたUboundを取得(変数に格納した最大Tab区切り数(TabMax)
    と比較しその行のTab区切り数の方が多かったら変数にTab区切り数(TabMax)を格納しなおす)

 4 配列の列数(TabMax)・行数を設定

 5 テキストファイルの内容をループで配列に格納

 6 配列の内容をリストボックスに一括転記

 としています。

 テキストファイルの行数・列数はそれほど多くない(行数は多くても500程度・列数は5程度)ので上記の
 方法でもさほどストレスは感じていませんが、もし一発で最大Tab区切り数を取得する方法があればと思い
 質問させていただきました。

 もし方法がありましたらご教示お願いいたします。

 ウィンドウズはXP(SP3) エクセルは2002です。よろしくお願いいたします。

 現状のコードは以下の通りです。

 Private Sub UserForm_Initialize()
  Dim txtpath As String
  Dim txtstr As String
  Dim spA As Variant
  Dim spB As Variant
  Dim i As Integer
  Dim j As Integer
  Dim lbary() As Variant
  Dim RowNum As Long
  Dim clcnt As Integer
  Dim gyoutabnum As Integer
   '読込むテキストファイルの指定
   txtpath = ThisWorkbook.Path & "\aaa.txt"
   'テキストファイルの内容取得(Function呼び出し)
   txtstr = txtget(txtpath)
   '最大Tab区切り数取得(Function呼び出し)
   clcnt = TabMax(txtstr)
   'テキストファイル内容を改行(VbCrLf)でSplit
   spA = Split(txtstr, vbCrLf)
   RowNum = UBound(spA)
   '配列の列数・行数を設定
   ReDim lbary(clcnt, RowNum)
   For i = 0 To UBound(spA)
    '各行の内容をTabでSplit
    spB = Split(spA(i), vbTab)
    gyoutabnum = UBound(spB)
    For j = 0 To gyoutabnum
     'Tabで区切ったものを配列に格納
     lbary(j, i) = spB(j)
    Next j
   Next i
   '配列の内容をリストボックスに格納
   Me.ListBox1.ColumnCount = clcnt - 1
   Me.ListBox1.Column = lbary
   Erase lbary
 End Sub

 '最大Tab区切り数を取得するFunction
 Function TabMax(ByVal txtstr As String) As Integer
  Dim spA As Variant
  Dim spB As Variant
  Dim gyoutabnum As Integer
  Dim i As Long
   '文字列をVbCrlfでSplit
   spA = Split(txtstr, vbCrLf)
   'tabmax(最大Tab区切り数)の初期化)
   tabmaxget = 0
   For i = 0 To UBound(spA)
    '各行の文字列をVbCrlfでSplit
    spB = Split(spA(i), vbTab)
    '各行のTab区切り数を取得
    gyoutabnum = UBound(spB)
    '各行のTab区切り数がtabmax(最大Tab区切り数)より大きかったら
    'tabmaxに各行のTab区切り数を再格納
    If gyoutabnum > TabMax Then TabMax = gyoutabnum
   Next i
 End Function

 'テキストファイル内容を取得するFunction
 Function txtget(ByVal txtpath As String)
  Dim FSO As Object
  Dim f As Object
  Dim txtstr As String
   Set FSO = CreateObject("Scripting.FileSystemObject")
   Set f = FSO.OpenTextFile(txtpath)
   If FSO.getfile(txtpath).Size = 0 Then
      txtget = ""
   Else
      txtget = f.ReadAll
   End If
   Set FSO = Nothing
 End Function

 私なら、テキストファイルウィザードでシートに展開して
RowSourceプロパティに展開した範囲を指定しちゃいます。
(みやほりん)

 みやほりんさん、ご回答ありがとうございます。

 下記のコードでテキストファイルの内容を一括でリストボックスに格納することは出来ました。

 Private Sub CommandButton1_Click()
  Dim fpath As String
  Dim wb As Workbook
  Dim r As Range
   Me.ListBox1.Clear
   fpath = ThisWorkbook.Path & "\aaa.txt"
   Application.ScreenUpdating = False
   Workbooks.OpenText Filename:=fpath, DataType:=xlDelimited, Comma:=True
   Set wb = ActiveWorkbook
   Set r = ActiveSheet.UsedRange
   Me.ListBox1.List = r.Value
   Me.ListBox1.ColumnCount = r.Columns.Count
   wb.Close , False
   Application.ScreenUpdating = True
   Set r = Nothing
   Set wb = Nothing
 End Sub

 やはり一度シートに展開する方法しかないようですね。
 メモリ上で一発で最大タブ区切り数を取得する方法は無いかなと思ったのですが無い
 ようですね。

 メモリ上で取得できたら他の事にも応用できそうでしたが取得出来ないので他のアプローチ
 を考えてみます。

 ありがとうございました。

 (カシスソーダ)

 >やはり一度シートに展開する方法しかないようですね。
 >メモリ上で一発で最大タブ区切り数を取得する方法は無いかなと思ったのですが無い
 >ようですね。

 ADOを使えば可能ですが、大きくは変わらないと思いますよ

 新規ブックを作成してください。
 UserForm1を作成し、リストボックス(ListBox1)を一つ配置してください。

 標準モジュール(Module1)にADO関連プロシジャー群

 '======================================================
 Private cn As Object
 '=============================================================
 Function open_ado_text(path As String) As Long 'adoでテキストにアクセス
    On Error Resume Next
    Dim link_opt As String
    Set cn = CreateObject("adodb.connection")
    link_opt = "Driver={Microsoft Text Driver (*.txt; *.csv)};" & _
                 "DBQ=" & path & ";" & "ReadOnly=0"
    cn.Open link_opt
    open_ado_text = Err.Number
    On Error GoTo 0
 End Function
 '=============================================================
 Sub close_ado()    'クローズ
    On Error Resume Next
    cn.Close
    Set cn = Nothing
    On Error GoTo 0
 End Sub
 '=============================================================
 Function exec_sql(sql_str, Optional rs As Variant) As Long  'Sqlの実行
    On Error Resume Next
    If IsMissing(rs) Then
       cn.Execute sql_str
    Else
       Set rs = cn.Execute(sql_str)
    End If
    exec_sql = Err.Number
    'If Err.Number <> 0 Then MsgBox Err.Description
    On Error GoTo 0
 End Function
 '==========================================================================
 Function mk_schema_ini(path As String, dat() As String) As Long
 'schema.iniの作成
    On Error GoTo err_mk_schema_ini
    Dim fno As Long
    Dim didx As Long
    mk_schema_ini = 0
    fno = FreeFile()
    Open path & "\schema.ini" For Output As #fno
    For didx = LBound(dat()) To UBound(dat())
       Print #fno, dat(didx)
       Next
    Close #fno
 ret_mk_schema_ini:
    On Error GoTo 0
    Exit Function
 err_mk_schema_ini:
    MsgBox Err.Description
    mk_schema_ini = Err.Number
    Resume ret_mk_schema_ini
 End Function
 '=============================================================
 Function del_schema_ini(path As String) 'schema_iniの削除
    On Error Resume Next
    Kill path & "\schema.ini"
    On Error GoTo 0
 End Function

 別の標準モジュール(Module2)にテキストファイルをListbox1に登録し、表示するプロシジャー

 '==============================================================
 Sub test()
    Dim ret As Long
    Dim dat(1 To 4) As String
    Dim rs As Object
    Dim ans As Variant
    dat(1) = "[smp.txt]"
    dat(2) = "ColNameHeader = false"
    dat(3) = "CharacterSet = oem"
    dat(4) = "Format = TabDelimited"
    Call mk_schema_ini(ThisWorkbook.path, dat())
    ret = open_ado_text(ThisWorkbook.path)
    If ret = 0 Then
       ret = exec_sql("select * from smp.txt", rs)
       If ret = 0 Then
          With UserForm1
             .ListBox1.ColumnCount = rs.Fields.Count
             .ListBox1.Column = rs.GetRows
             .Show
          End With
       Else
          MsgBox Error(ret)
       End If
       rs.Close
       close_ado
       End If
    Call del_schema_ini(ThisWorkbook.path)
    Erase dat()
    Set rs = Nothing
 End Sub

 上記ブックは、対象のテキストファイル(ファイル名 smp.txt、タブ区切りでヘッダーなしの例)と
 同じフォルダ上に保存した上で実行してみてください。

 ファイル名が違うならコード解析の上変更してください

 ichinose


 ichinoseさん、ご回答ありがとうございます。

 >Sub test()
 ↑の
 >         With UserForm1
 >            .ListBox1.ColumnCount = rs.Fields.Count
 >            .ListBox1.Column = rs.GetRows
 >            .Show
 >         End With

 >rs.Fields.Count

 が最大Tab区切り数になるということですね。
 ありがとうございました。

 (カシスソーダ)

コメント返信:

[ 一覧(最新更新順) ]


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