スポンサーリンク

Ooo Calc Basicマクロで,シート内の特定セル領域をCSV出力するサンプルコード。ブックと同じフォルダ上にタブ区切りで複数データを書き出し

Excel/Wordオフィス製品のTipsまとめへ


OpenOffice.org CalcのBasicマクロで,シート内容をCSV出力するサンプルコード。

特定のシートの行・列領域を指定し,
ブックと同じフォルダ上にTSV(タブ区切りCSV)形式で保存する。

シート全体をCSV変換するのではなく,
開始行や開始列・終了列を指定できるのがポイント。

行方向にデータが存在する限り,全件がCSV出力される。

' タブ区切りCSV(TSV)に書き出し
Sub export_tsv

	' タブ区切りCSV文字列を取得
	s = getRangeAsTsvText( 0, 6, 1, 2 )  
	' ↑シート番号,開始行,開始列,終了列を指定
	
	' 書き出し
	output_txt s, getThisWorkbookPath & "exported_tsv.txt"
	
	msgbox "書き出しました。"
End Sub


' あるシートの指定された領域内を,
' タブ区切りCSVとして文字列で返す。
' シート番号,開始行,開始列,終了列を指定する。
' 終了行は指定不要で,列内でデータが存在する最後の行まで自動継続。
' 各番号は0始まりで指定すること。
Function getRangeAsTsvText( sheet_index, y_start, x_start, x_end )
	
	' 定数
	br = Chr(13) ' 改行
	tb = Chr(9) ' タブ

	' 終了行の番号を取得
	y_end = EndXlDownInSheet( sheet_index, x_start )
		' msgbox "y_end = " & y_end

	' シート
	sheet = ThisComponent.Sheets( sheet_index )
	
	' 文字列構築を開始
	s = ""
	
	' 全行について
	For y = y_start To y_end
		
		' 全列について
		For x = x_start To x_end
			' セルを取得
			cell = sheet.getCellByPosition(x, y)
		
			' セル内容の型を取得
			cell_type = cell.getType
				
			' 型に応じた方法で,セル内容を取得
			cell_value = ""
			Select Case cell_type 
				Case com.sun.star.table.CellContentType.TEXT
					' テキストなら,文字列として取得
					'cell_value = cell_value & "T" 
					cell_value = cell_value & cell.String

				Case com.sun.star.table.CellContentType.EMPTY
					'cell_value = cell_value & "E" 
					cell_value = cell_value &  ""

				Case com.sun.star.table.CellContentType.FORMULA
					'cell_value = cell_value & "F" 
					cell_value = cell_value & cell.Value

				Case com.sun.star.table.CellContentType.VALUE
					'cell_value = cell_value & "V" 
					cell_value = cell_value & cell.Value

			End Select
			
			' セル内容を結合
			s = s & cell_value
			
			' タブを付与
			If x < x_end Then
				s = s & tb
			End If
		Next x
		
		' 改行を付与
		If y < y_end Then
			s = s & br
		End If
	Next y
	
	Msgbox "CSV文字列が準備できました。文字列の長さ:" & Len(s)
	' OOo Basicには文字列変数の長さが65535文字までなので上限に注意すること

	getRangeAsTsvText = s
	
End Function


' ファイル書き出し
' http://computer-technology.hateblo.jp/entry/20150914/p3
Sub output_txt( s, output_path )
	'msgbox output_path

	' ファイルを開く。新規作成も上書きもOK
	fp = FreeFile 
	Open output_path For Output As #fp

	' 書き込み
	Print #fp, s

	' 終了
	Close #fp
End Sub
	

' このブックの存在するフォルダをフルパスで返す。
' Excel VBAでの ThisWorkbook.Pathに相当
' http://computer-technology.hateblo.jp/entry/20150914/p2
Function getThisWorkbookPath

	' このブックのフルパスをURLとして取得
	encoded_url = ThisComponent.getURL
	
	' URLをWindows用のパスに変換
	windows_filepath = ConvertFromUrl(encoded_url )
	
	' ファイルパスからディレクトリパスを抽出
	windows_dir_path = file_path_to_dir_path(windows_filepath)

	getThisWorkbookPath = windows_dir_path
	
End Function


' ファイルのフルパスから,
' ファイルの存在するディレクトリのパスを
' Windowsの形式で抽出する。
' 末尾に\を含む文字列が返る。
' http://computer-technology.hateblo.jp/entry/20150914/p1
Function file_path_to_dir_path(file_path)
	' 左から何文字分を抽出すればよいか
	str_length = 0
	
	' 何文字目に\があるか,という毎回の検索結果
	match_index = 1
	
	' \が見つかる限り検索を続ける
	Do While match_index <> 0
		
		' 前回見つかった位置よりも後で\を探す
		match_index = InStr(match_index + 1, file_path, "\")
		
		' \が見つかった場合
		If match_index <> 0 Then
			str_length = match_index
		End If
		
	Loop
	
	' ファイルパスから,左から指定文字数だけ抽出
	s = Left(file_path, str_length)
	
	file_path_to_dir_path = s

End Function



' ----------- Excel VBAとの互換機能のコード ----------- 



' 引用元:
' http://computer-technology.hateblo.jp/entry/20150524/p1


' あるシート内で,ある列の中に最後にデータが存在する行番号を0始まりで返す。
' Excel VBAの End(xlDown) のパクリ。
' 引数のシート番号と列番号は0始まりで指定すること。
Function EndXlDownInSheet( sheet_index, column_index )
	
	' シート
	oSheet = ThisComponent.Sheets( sheet_index )

	' シート内の特定の列
	oColumn = oSheet.getColumns().getByIndex(column_index)
	
	' セル検索用の定数
	magic_number = 31
	
	' 列内から,「値の入っている一続きのセル範囲」を複数取得
	oRanges = oColumn.queryContentCells(magic_number)

	' ひとつながりの領域がいくつあるか
	nRangeCount = oRanges.getCount()
	
	' 一つながりの領域が1つもなかったら
	If nRangeCount = 0 Then
		' どこにもデータはない
		nBottomRow = -1
	Else
		' 最後に現れる一つながりの領域
		oRange = oRanges.getByIndex(nRangeCount - 1)
		
		' その領域内で,データが入っている最終行の番号 (0始まり)
		nBottomRow = oRange.getRangeAddress().EndRow
	End If
	
	' 返却値
	EndXlDownInSheet = nBottomRow

End Function

工夫した点:

  • セルの内容が数値なのか,文字列なのか?によって,.Value や .String を使い分けている。
    • そのために,cell.getType() でセル内容の型を判定している。
  • データが存在する限り全行をスキャンするために,下方向に最後のデータが存在する行番号を取得している。
  • シート内容をCSV文字列に変換するルーチンと,文字列をファイル保存するルーチンを分離している。
    • しかし注意点として,OOo Basicでは文字列変数に格納できる文字データの長さが最大6万5千文字ほどなので,この上限以内でしかデータ処理できない。


このコードを実現するために必要になった共通関数:

Ooo Calc Basicマクロで,ブックと同じフォルダ上でテキストファイルに書き込みするサンプルコード。シート上の情報をテキスト出力する最も簡単な方法
http://computer-technology.hateblo.jp/entry/20150914/p3

  • テキストファイルに書き込みする一番簡単なサンプルコード。 テキストファイルは,ブックと同じフォルダ上に,自動的に新規作成される。


Ooo CalcのBasicマクロで,ブックの存在するフォルダのフルパスを取得する関数のサンプルコード。Excel VBAのThisWorkbook.Pathのように親ディレクトリを返す
http://computer-technology.hateblo.jp/entry/20150914/p2

  • ブックの保存されているフォルダのフルパスを一発で取得する関数


Ooo Calc Basicマクロで,ファイルパスをフォルダパスに変換する関数のサンプルコード。Windows用のフルパス文字列から親ディレクトリのパスを抽出するOpenOffice.org用コード
http://computer-technology.hateblo.jp/entry/20150914/p1

  • ファイルパスをディレクトリパスに変換するコード。


OOo CalcのBasicマクロで,「値のある最後の行や列」を取得する方法。Excel VBAのEnd(xlDown), End(xlToRight)と同じ目的のサンプルコード
http://computer-technology.hateblo.jp/entry/20150524/p1

  • Excel VBAでいう End(xlDown) ・ End(xlToRight) を, OpenOffice.org CalcのBasicマクロで実現した。


「セル内容の型」の判定方法について:

AddinBox/VBAユーザーの為のOpenOffice.org 備忘録:Value でセルの文字列は取れない
http://blog.livedoor.jp/addinbox/arch...

  • VBAなら、セルに入っている「数値」も「文字列」も【 Value 】プロパティで取れます。
    • でも、OOo.Basic では、文字列セルを Value プロパティで取ると、結果は『ゼロ ( 0 ) 』
    • 文字列セルから、セル値を得るには【 String 】プロパティで取ります。


OOoBasic/Calc/contenttype - ...?
http://hermione.s41.xrea.com/pukiwiki...

  • セル内容の型は getType() メソッドを使用して取得します。


Spreadsheet common - Apache OpenOffice Wiki
https://wiki.openoffice.org/wiki/Spre...

  • 型が文字列なら,getTypeの返り値はcom.sun.star.table.CellContentType.TEXT


セルと範囲 - Apache OpenOffice Wiki
https://wiki.openoffice.org/wiki/JA/D...

  • Cell.Type 属性を使うと、セルの内容の種類を示す com.sun.star.table.CellContentType の値を取得できます。


その他,このコードを作成するために参考にした基礎的な情報。

SelectとかFor文とか,意外と使わないのでリファレンスが必要:

OpenOffice.org Basic - Wikibooks
https://ja.wikibooks.org/wiki/OpenOff...

  • 'SELECT CASE' で指定した値と同じものを、上から順に 'CASE' 行で探し、 値が同じなら、対応するブロックを実行します。


OOoBasic/Calc/cell - ...?
http://hermione.s41.xrea.com/pukiwiki...

  • 単一のセルオブジェクトを取得するために getCellByPosition メソッドを利用します。
  • 引数には列、行の順に取得するセルのインデックスを指定します。
  • インデックスは "0" から始まります。


ループ - Apache OpenOffice Wiki
https://wiki.openoffice.org/wiki/JA/D...

  • For I = 1 To 10
  • ' ... Inner part of loop
  • Next I


文字列変数 - Apache OpenOffice Wiki
https://wiki.openoffice.org/wiki/JA/D...

  • OpenOffice.org Basic では、文字列変数を Unicode で保存します。
  • 1 つの文字列変数には、最大 65535 文字を格納できます。


Excel/Wordオフィス製品のTipsまとめへ