LoginSignup
0
0

More than 5 years have passed since last update.

LibreOffice Calc で組んだマクロ

Last updated at Posted at 2017-02-20

現金出納帳を LibreOffice Calc で作ろうかと思ったんだが、
そういえば ゲーム用のスプレッドシートを作っていたときに
いくつか マクロを組んだんだった。

ちなみに そっちのゲームの方は 高校簿記のバランスシートの借方、貸方をヒントに
ベテランがぶち切れそうな インデント・スタイルのマクロにしたのだった。

Code モジュール

REM  *****  BASIC  *****
' Copyright (c) 2017 TAKAHASHI Satoshi (Handle: Muzudho)(Dojin circle: "Grayscale")
' Released under the MIT license
' http://opensource.org/licenses/mit-license.php

Option Explicit

'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
'   1   2   3   4   5   6   7   8   9   0   1   2   3   4   5   6   7   8   9   0   1   2   3   4   5   6   7   8   9   0   1   2   3   4   5   6   7   8   9   0
'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' コーディングの列幅を短くするためのライブラリです。

                                                                                                                                ' このコードで使われている命名の略称表記
    ' dc    ... document
    ' sh    ... sheet
    ' cm    ... column
    ' rw    ... row
    ' ce    ... cell
    ' vl    ... value

'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' 文書を新規作成 CreateDocument
Sub CreateDc    (   )   As Object
    CreateDc                                                    =   StarDesktop.loadComponentFromURL( _
                                                                        "private:factory/scalc" ,"_blank"   ,0  ,Array()    )
End Sub

'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' 文書を読込   GetDocument
                                                                                                                                ' dcFile        .odsファイルへのパス
Sub GetDc   (   dcFile  As String   )   As Object
    GetDc                                                       =   StarDesktop.loadComponentFromURL(   _
                                                                        ConvertToUrl(dcFile)    ,"_blank"   ,0  ,Array() )
End Sub

'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' 文書を保存して閉じる    SaveAndCloseDocument
                                                                                                                                ' dc            文書
                                                                                                                                ' dcFile        .odsファイルへのパス
Sub SaveAndCloseDc  (   dc As Object    ,dcFile As String   )
                                                                                                                                ' .odsとして保存
    dc.storeAsURL(  ConvertToUrl( dcFile )  ,Array()    )
                                                                                                                                ' ファイルを閉じる
    dc.dispose
End Sub

'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' シート挿入   InsertSheet
                                                                                                                                ' dc            文書
                                                                                                                                ' shName        シート名
                                                                                                                                ' position      シートを差し込む位置。左端が0
Sub InsertSh    (    dc As Object   ,shName As String _
                    ,position As Integer    )
    dc.getSheets().insertNewByName( shName ,position )
End Sub

'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' シートをアクティブにします SetActiveSheet
                                                                                                                                ' dc            文書
                                                                                                                                ' sh            シート
Sub SetActiveSh (   dc As Object    ,sh As Object   )
    dc.getCurrentController().setActiveSheet( sh )
End Sub

'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' シート取得   GetSheet
                                                                                                                                ' dc            文書
                                                                                                                                ' shName        シート名
Sub GetSh   (   dc As Object    ,shName As String   ) As Object
    GetSh                                                       =   dc.getSheets().getByName( shName )
End Sub

'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' シート存在判定 HasSheet
                                                                                                                                ' dc            文書
                                                                                                                                ' shName        シート名
Sub HasSh   (   dc As Object    ,shName As String   ) As Boolean
    HasSh                                                       =   dc.getSheets().hasByName(   shName  )
End Sub

'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' セル取得      GetCellObject
                                                                                                                                ' sh            シート
                                                                                                                                ' cm            列番号(0スタート)
                                                                                                                                ' rw            行番号(0スタート)
Sub GetCeOb (   sh As Object    ,cm As Integer  ,rw As Integer  ) As Object
    GetCeOb                                                     =   sh.getCellByPosition(  cm  ,rw  )
End Sub

'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' セルの値を取得 GetCell
                                                                                                                                ' sh                シート
                                                                                                                                ' cm                列番号(0スタート)
                                                                                                                                ' rw                行番号(0スタート)
Sub GetCe ( sh As Object    ,cm As Integer  ,rw As Integer  ) As String
    GetCe                                                       =   sh.getCellByPosition(  cm  ,rw  ).String
End Sub

'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' セルに値を設定 SetCell
                                                                                                                                ' sh                シート
                                                                                                                                ' cm                列番号(0スタート)
                                                                                                                                ' rw                行番号(0スタート)
                                                                                                                                ' vl                設定したい値
Sub SetCe ( sh As Object    ,cm As Integer  ,rw As Integer  , vl As String  )
    sh.getCellByPosition(  cm  ,rw  ).String                    =   vl
End Sub

'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' セルからセルへ値を複写 CopyCell
                                                                                                                                ' sh0               シート
                                                                                                                                ' cm0               列番号(0スタート)
                                                                                                                                ' rw0               行番号(0スタート)
                                                                                                                                ' sh1               シート
                                                                                                                                ' cm1               列番号(0スタート)
                                                                                                                                ' rw1               行番号(0スタート)
Sub CopCe (  sh0 As Object      ,cm0 As Integer     ,rw0 As Integer _
            ,sh1 As Object      ,cm1 As Integer     ,rw1 As Integer )
    sh0.getCellByPosition(  cm0  ,rw0  ).String                 =   sh1.getCellByPosition(  cm1  ,rw1  ).String
End Sub

'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' カウントアップ(カウントダウン)
                                                                                                                                ' vl                更新したい変数
                                                                                                                                ' offset            増減する量
Sub CountUp (   vl As Integer   , offset As Integer )
    vl = vl + offset
End Sub

'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' 文字列を末尾に追加
                                                                                                                                ' vl                更新したい変数
                                                                                                                                ' tail              追加したい文字列
Sub AppendTail  (   vl As String    ,tail As String )
    vl = vl & tail
End Sub

Utility モジュール

REM  *****  BASIC  *****
' Copyright (c) 2017 TAKAHASHI Satoshi (Handle: Muzudho)(Dojin circle: "Grayscale")
' Released under the MIT license
' http://opensource.org/licenses/mit-license.php

Option Explicit

'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
'   1   2   3   4   5   6   7   8   9   0   1   2   3   4   5   6   7   8   9   0   1   2   3   4   5   6   7   8   9   0   1   2   3   4   5   6   7   8   9   0
'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' CSV読込、シート検索ライブラリ

                                                                                                                                ' このコードで使われている命名の略称表記
    ' dc    ... document
    ' sh    ... sheet
    ' cm    ... column
    ' rw    ... row
    ' ce    ... cell
    ' vl    ... value

'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' CSVファイルを読込んでシートに書き写します
Sub ReadCsv( dc As Object, filename As String, sh as Object)
                                                                                                                                ' シートをアクティブにします
    Code.SetActiveSh(   dc  ,sh )

    If Not FileExists( filename ) Then
        Msgbox( filename & _
            " ファイルがありません。エクスポートしましたか?")
    End If
                                                                                                                                ' 外部ファイルの内容をシートに読込みます
    Dim fileHandle                                              As  Integer
    fileHandle = Freefile
    Open filename For Input As fileHandle

    Dim rw                                                      As  Integer
    Dim source                                                  As  String
    rw = 0
    Do While not eof(fileHandle)
        Line Input #fileHandle, source

        Utility.CsvLineParser(  sh  ,rw                         ,   source      )
        Code.CountUp( rw, 1 )
    Loop

    Close #fileHandle
End Sub

'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' CSV文字列を読込み、シートに入れます

                                                                                                                                ' sh        設定先シート
                                                                                                                                ' rw        設定先行番号(0スタート)
                                                                                                                                ' source    読込む1行分のCSV文字列
Sub CsvLineParser( _
                     sh     As Object   _
                    ,rw     As Integer  _
                    ,source As String   _
                 )

                                                                                                                                ' 空文字列なら何もしません
    If Len(source) < 1 Then
        Exit Sub
    End If
                                                                                                                                ' caret     何文字目か。(1スタート)
                                                                                                                                ' cm        列番号 (0スタート)
                                                                                                                                ' vl_ce     1セル分の文字列
    Dim caret                                                   As  Integer
    Dim cm                                                      As  Integer
    Dim vl_ce                                                   As  String
    caret                                                       =   1
    cm                                                          =   0
    vl_ce                                                       =   ""

                                                                                                                                ' このループで1行分に対応
                                                                                                                                ' 最後の文字でなければ(caret-1)実行
    Do While caret-1 < Len(source)
        Select Case Mid(source,caret,1)
                                                                                                                                ' カンマを読込んだら、溜めているセル値を出力して次へ
            Case ",":
                Code.CountUp( caret ,1 )
                Code.SetCe  ( sh    ,cm     ,rw                 ,   vl_ce   )
                Code.CountUp( cm    ,1 )
                vl_ce                                           =   ""

                                                                                                                                ' ダブルクォーテーションを読込んだら、リテラル文字列処理へ
            Case """":
                Code.CountUp( caret ,1 )
                                                                                                                                ' エスケープしながら、単独「"」が出てくるまでそのまま出力
                Do While caret-1 < Len(source)
                    If """"=Mid(source,caret,1) Then
                                                                                                                                ' 「"」が最後の文字だったのなら、無視してループ抜け
                        If caret + 1 - 1 = Len(source) Then
                            Code.CountUp( caret ,1 )
                            Exit Do
                                                                                                                                ' 2連続の「"」なら1つの「"」に変換してループ続行
                        ElseIf _
                            """" = Mid(source,caret+1,1) _
                        Then
                            Code.CountUp( caret ,2 )
                            Code.AppendTail(    vl_ce           ,   """"    )
                        Else
                                                                                                                                ' 2連続でない「"」なら、次の「,」の次までの空白等をスキップしてループ抜け。(2012-10-30 変更 旧:index++;)(2017-02-01 変更 旧:index+=2;)
                            caret                               =   InStr( caret, source, "," )
                            Code.CountUp( caret ,1 )
                            Exit Do
                        End If
                    Else
                                                                                                                                ' 通常文字なので読み取ってループ続行
                        Code.AppendTail(    vl_ce               ,   Mid(source,caret,1) )
                        Code.CountUp( caret ,1 )
                    End If
                Loop
                                                                                                                                ' 前後の空白はカット
                Code.SetCe( sh      ,cm ,rw                     ,   Trim(vl_ce) )
                Code.CountUp( cm ,1 )
                vl_ce                                               =   ""
                                                                                                                                ' ダブルクォートされていない文字列か、ダブルクォートの前のスペースはそのまま読取
            Case Else:
                Code.AppendTail(    vl_ce                       ,   Mid(source,caret,1) )
                Code.CountUp( caret ,1 )
        End Select
    Loop
End Sub

'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' カンマや、ダブルクオーテーションを含む文字列を、
                                                                                                                                ' ダブルクォーテーションで挟みます。
                                                                                                                                ' この際、ダブルクォーテーション1つは 2つ に変換します。

                                                                                                                                ' source    セル1つ分のCSV文字列
Sub EscapeCsv(source As String) As String
                                                                                                                                ' エスケープが必要なら真
    Dim isEscape                                                As  Boolean
        isEscape                                                =   false

    Dim str                                                     As  String
    str                                                         =   ""

                                                                                                                                ' caret     何文字目か。(1スタート)
    Dim caret                                                   As  Integer
    For caret = 1 To Len(source)
                                                                                                                                ' カンマが含まれていれば、エスケープを必要扱いにします。
                                                                                                                                ' (2017-02-09 追加 LF改行コード10、CR復帰コード13 が含まれていれば、エスケープを必要扱いにします)
        If _
            ","= Mid( source, caret, 1 ) Or _
            Chr$(10) = Mid( source, caret, 1 ) Or   _
            Chr$(13) = Mid( source, caret, 1 )      _
        Then
            isEscape                                            =   true
            Code.AppendTail(    str                             ,   Mid( source, caret, 1 ) )
        ElseIf """" = Mid( source, caret, 1 ) Then                                                                              ' ダブルクォーテーションが含まれていたので、エスケープが必要になりました
            isEscape                                            =   true
            Code.AppendTail(    str                             ,   """"""  )                                                   ' ダブルクォーテーションを、1つの代わりに2つ追加
        Else
            Code.AppendTail(    str                             ,   Mid( source, caret, 1 ) )
        End If
    Next
                                                                                                                                ' 必要なら、ダブルクォーテーションで挟みます
    If isEscape Then
        str                                                     =   """" & str & """"
    End If

    EscapeCsv                                                   =   str
End Sub

'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' 行番号をシート検索

                                                                                                                                ' vl_expected   探して一致したい行値
                                                                                                                                ' sh_target     探すシート
                                                                                                                                ' cm_target     探す列
                                                                                                                                ' rw_first      探し始める行
                                                                                                                                ' rw_lastOver   最終行の次
Sub RowOf(  _
             vl_expected    As String   _
            ,sh_target      As Object   _
            ,cm_target      As Integer  _
            ,rw_first       As Integer  _
            ,rw_lastOver    As Integer  _
         ) As Integer   
    Dim rw                                                      As Integer
    For rw = rw_first To rw_lastOver - 1
        If _
            vl_expected = Code.GetCe( sh_target _
                ,cm_target  ,rw ) _
        Then
            RowOf                                               = rw
            Exit Sub
        End If
    Next

    RowOf                                                       = -1
End Sub

'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' 列番号をシート検索

                                                                                                                                ' vl_expected   探して一致したい列値
                                                                                                                                ' sh_target     探すシート
                                                                                                                                ' rw_target     探す行
                                                                                                                                ' cm_first      探し始める列
                                                                                                                                ' cm_lastOver   最終列の次
Sub ColumnOf(   _
                 vl_expected    As String   _
                ,sh_target      As Object   _
                ,rw_target      As Integer  _
                ,cm_first       As Integer  _
                ,cm_lastOver    As Integer  _
            ) As Integer    
    Dim cm                                                      As  Integer
    For cm = cm_first To cm_lastOver - 1
        If _
            vl_expected = Code.GetCe( sh_target ,cm _
                                    ,rw_target ) Then
            ColumnOf                                            =   cm
            Exit Sub
        End If
    Next

    ColumnOf                                                    =   -1
End Sub


'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' セル値をシート検索

                                                                                                                                ' vl_foreignKey 探して一致したい値
                                                                                                                                ' sh_target     探すシート
                                                                                                                                ' cm_key        探す列
                                                                                                                                ' cm_value      取得したい値が入っている列
Sub VLookup(    _
                 vl_foreignKey  As String   _
                ,sh_target      As Object   _
                ,cm_key         As Integer  _
                ,cm_value       As Integer  _
           ) As String
    Dim rw_foreignSheet                                         As  Integer
    rw_foreignSheet                                             =   0

    Do While "[EOF]" <> Code.GetCe( sh_target   _
                                    ,0  ,rw_foreignSheet    )
        If _
            vl_foreignKey = Code.GetCe( sh_target _
                ,cm_key ,rw_foreignSheet    )   _
        Then
            VLookup                                             =   Code.GetCe( sh_target   ,cm_value   ,rw_foreignSheet    )
            Exit Sub
        End If
        Code.CountUp(   rw_foreignSheet                         ,   1   )
    Loop

    VLookup                                                     = "#NotFound#"
End Sub

'---------------------------------------------------------------=---------------------------------------------------------------'--------------------------------
                                                                                                                                ' 2列を ドットでつないで 1つのキーにします
Sub ConcatKey2(  sh             As Object   _
                ,cm0            As Integer  _
                ,cm1            As Integer  _
                ,rw             As Integer  _
                ,joinDelimiter  As String   _
              ) As String
    Dim key1                                                    As  String
    Dim key2                                                    As  String
        key1                                                    =   Code.GetCe( sh  ,cm0  ,rw  )
        key2                                                    =   Code.GetCe( sh  ,cm1  ,rw  )
    ConcatKey2                                                  =   key1  &  joinDelimiter  &  key2
End Sub

                                                                                                                                ' 3列を ドットでつないで 1つのキーにします
Sub ConcatKey3(  sh             As Object   _
                ,cm0            As Integer  _
                ,cm1            As Integer  _
                ,cm2            As Integer  _
                ,rw             As Integer  _
                ,joinDelimiter  As String   _
              ) As String
    Dim key1                                                    As  String
    Dim key2                                                    As  String
    Dim key3                                                    As  String
        key1                                                    =   Code.GetCe( sh  ,cm0  ,rw  )
        key2                                                    =   Code.GetCe( sh  ,cm1  ,rw  )
        key3                                                    =   Code.GetCe( sh  ,cm2  ,rw  )
    ConcatKey3                                                  =   key1  &  joinDelimiter  &  key2  &  joinDelimiter  &  key3
End Sub

よーし、ライブラリを再利用するぜ。

あっ、MITライセンスにしとこ……。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0