VBA.Split()が動かない

エクセル(32bit)で使用していた自作関数のマクロを、リブレオフィス(32bit)で使用しようとしていて、壁にあたっています。完全な初心者です。JavaScriptなども書けません。(会社が一斉にリブレオフィスに移行したから)



ネットで何処を探しても該当する情報が得られずヤフー知恵袋でも質問していますが解決に至りません。情報を探しているうちにこのページと出会いました。



3つ悩んでいるのですが、別々のスレッドで質問させていただきます。

ここでは***「セル内の文章を分割する自作関数」***に関する質問です。



以下の自作関数が、エクセルでは問題なく動いていました。

単純に、住所の文字列(区切るべき場所に#が入ってる)を分割します。

これが動かないのです。

'最初の2行はリブレ側で追加
Rem Attribute VBA_ModuleType=VBADocumentModule
Option VBASupport 1
Option Explicit

'包丁で住所を切り刻む

Function 住所分割(元々のん As Range, 包丁 As String) As Variant
住所分割 = VBA.Split(元々のん.Value, 包丁)

End Function
ここでの質問に至るまでの経緯も記載します。

***<Step1>***
リブレオフィスではオブジェクトの先頭に、

Rem Attribute VBA_ModuleType=VBAModule
Option VBASupport 1
を追記すれば VBAProject が出現してエクセルマクロが動かせるとわかりました。
ゆえにそうしたのですが、

住所分割 = VBA.Split(元々のん.Value, 包丁)
のところで、

BASIC ランタイムエラー.
'12'
VBA
と出てしまいました。

ランタイムがどういうものかよく理解できていないのですが、
バージョンがあわないのかな?と思ったりしていました。

どう書き直しせばよいうのかわからずにヤフー知恵袋で質問しました。
まず最初に、以下の回答が得られました。

Option ExplicitなのにVBAという変数が定義されていないよというエラーです。
もともとSplitはVBA上の関数でありVBA.という記述は不要でした。
またLibre側はVBA.の記法をサポートしていないようです。
よってVBA.を記述から削ってください。
***<Step2>***
ヤフー知恵袋での回答に従って以下のように変えました。

Rem Attribute VBA_ModuleType=VBADocumentModule
Option VBASupport 1
Option Explicit

Function 住所分割(元々のん As Range, 包丁 As String) As Variant
住所分割 = Split(元々のん.Value, 包丁)

End Function
もしかしたらリブレではエクセルと違って
2バイトの日本語記述は駄目なのかも?とも思い、
以下も試しました。

Rem Attribute VBA_ModuleType=VBADocumentModule
Option VBASupport 1

Option Explicit

Function JBunkatsu(MotoMoto As Range, Houcyou As String) As Variant
JBunkatsu = Split(MotoMoto.Value, Houcyou)

End Function
結果的に、このどちらでも以下の警告が出てしまいました。

BASIC ランタイムエラー.
'91'
オブジェクト変数は設定できていません。

そこで再び、ヤフー知恵袋で質問しました。
以下の返信が得られました。

Functionの中でオブジェクトは使ってないので、
Functionを呼び出したSubプロシージャ側の問題と思われます。
となると、これの場合の"Subプロシージャ"とは、
リブレが呼び出すライブラリ(←と呼べば呼べば良いのでしょうか)のことですか?

つまり、

Rem Attribute VBA_ModuleType=VBAModule
Option VBASupport 1

における、
"VBAModule"の中にあるプロシージャ、あるいは
"VBASupport 1"の中にあるプロシージャの事なのでしょうか?

もしそうであれば「互換性の問題で使えない」という解釈をすれば良いのでしょうか?

となれば。上記のコードは、たぶんJavaScriptで書かねばならないのでしょうが。
その場合、自作関数として、どう書けばよいのかがまるでわかりません。

よろしくご指導を願えれば幸いです。
一応Option VBASupport 1除いて両方動いたコード。

A1に"ABC" , A2に"DEF"をおいてます。本家VBAはValue(1,2)のような記法を採れないようだ。
Range(“A1:A2”)の戻り値はLibreOfficeにおいてはScVbaRangeであり、当該範囲に対するValueプロパティはVariant(1 to 2, 1 to 1)の型となる。
Option Explicit
Rem Attribute VBA_ModuleType=VBADocumentModule
Option VBASupport 1

Function JBunkatsu(MotoMoto As Variant, Houcyou As String) As Variant
JBunkatsu = Split(MotoMoto(1, 1), Houcyou)
End Function

Sub Main()
Dim x As Variant
x = Range(“A1:A2”).Value
MsgBox (JBunkatsu(x, “B”)(0))
End Sub

2018-12-10 不要な部分大幅改訂。編集前の状態は回答の履歴を見るべし。

自分なりの結論: Option VBASupport 1ありの状態で、第一引数Valueあり、添字なしの状態で、単独のセルをワークシート関数で使用した場合、エラーは出ない。

自分もやらかしているが、以下特に最後に記述する通り検証手順・時期の問題で問題を誤解した可能性が高いと考えている。

  • With構文の内部でピリオド始まりのところ
  • 比較
  • 算術演算
  • プロパティやメソッドの登場できるところ
  • 配列の添字の前
  • 引数リストの各要素
  • IsEmpty
  • 代入文

は、関数等の仕様がオブジェクトを望むものでない場合(少なくとも、Split関数の第一引数は文字列を要求する)、自動的にValueなどのデフォルトプロパティが存在するときは補われるらしく、また、ScVbaRangeのデフォルトプロパティであるValueプロパティはその範囲が単独のセルであるかどうかによって動作が変わり、単独のセルであるときはその内容を単独で返すようです。

https://opengrok.libreoffice.org/xref/core/sc/source/ui/vba/vbarange.cxx?r=ab9b67bb#1501

で、単独の値が返ったときには(1,1)というのをつけられないという理由でエラーになり、複数セルだったときには(1,1)がつけられ、単独の値になるためにエラーにならない。コードを変更して調査した感じだと、Split関数の第一引数は文字列型でなければならないため、文字列に変換できない「複数セルの範囲」を引数に与えることが仮に出来た場合、型変換の失敗を理由としたエラーになる。この二つのエラーは共にObject not setであるようだ。

なお、ワークシート関数としてJBunkatsuの第一引数に複数のセルを指定した場合、Excel VBAでは#Value!になるが、LibreOfficeのStarBasicはSplit関数がエラーメッセージを表示するダイアログを表示する。

Main関数は通常プログラミングコードのサンプルとしてここからスタートしてくれという意味を込めてつけられる。当初はワークシート関数としてではなく、StarBasicだけで完結させるつもりだろうと思っていたのでね。

それにしても…暗黙の型変換とかデフォルトプロパティとか嫌いだー

他にObject not setでエラーになるパターンとしてはExcelとLibreOfficeを往復する過程でOption VBASupport 1をつけ忘れたケースがある(俺も検証中に何回かやらかしている)

なお、ユーザー定義関数を含め、ワークシートに入力された式が再計算されるのは、式に対して変更を施したと認識されたとき、です。StarBasicのコードを変更した段階やセルでF2押してそのままEnterとかで安心しないように!

また、VBASupport 0では、ユーザー定義のワークシート関数は、オブジェクトや範囲を引数に出来ず、その内容が引数として渡されることにも注意が必要なようです。

なお、オブジェクトの引数の型は無視されると考えたほうが良いかも。インテリセンス専用。

上記のように、実験のタイミングや手順をよく検討しないと何が原因かの把握を間違えます

現状デフォルトプロパティを持つのはCOMを除けば本家VBA絡みだけです https://opengrok.libreoffice.org/search?q=getDefaultPropertyName&project=core

暇人さん?でよろしいのでしょうか?
早速のご回答、ありがとうございます。感謝いたします。

幾つか質問があります。おそらく超初心者の質問です。
心苦しいのですが、お付き合いを願えたら幸いです。

質問1
このコードは、
2つのセル(A1:A2)を関数内で指定してA1セル内の文章を指定文字で分割しています。

=JBunkatsu(A1,"B")

ではエラーが出ます。

=JBunkatsu(A1:A2,"B")

でなければ動いてくれません。

個人的には分割したいのはA1セルの中だけなのに?と感じてしまいます。
これは「そういうもの」だと丸呑みすべきなのでしょうか?
それとも「私が学習すべき何か」があるのであれば教えてください。

質問2
下側メッセージボックスを表示させるコードのようですが出現しません。
何故なのかがよくわかりません。
ちなみにこのコードを消してFunctionだけでも走ります。
何故なのでしょうか?よくわかりません

調査してみたいが、ちょっと予定外の作業が入って大幅に遅延中。少なくとも質問者は初心者にあらず、自分を卑下し過ぎかな。

(2019-12-09: 多分進捗50%くらい)

さらに調査を進めると、「質問者のVBAを取り除いたオリジナルのコード」であっても、JBunkatsuの第一引数がただ一つのセルを指す場合は成功しているように思う。

引数MotoMotoを書いたときの挙動が異なる?

実際のファイルがほしい。全く再現しなくなった。元々のコードで正常動作する。たまに「VBA Support 1」つけ忘れるけどorz

一所懸命にご回答くださっていたのに、返答が遅れてしまい申し訳ございませんでした。 年末に不幸が発生し、今日まで何もできずにいました。

ようやく気持ちを切り替えて、どうにかパソコンに向かっております。 ですが頭の中が空白の時間がとても長くなってしまい、取り戻すのに少し時間がかかりそうです。

ゆっくりと思い出しながら頂いたおい返事を、順番に理解しようと思います。 本当にありがとうございました。また、重ね重ね、申し訳ございませんでした。

RANGE1
RANGE2

参加したのが最近なのでこの古い質問にお答えしても
読んでいただけるかわかりませんけど、気づいたことがありますので。

新しくこの質問をご覧になった方も是非見てほしいと思います。

一番大事なのは、自分の目で見てみる事だと思うのです。
この質問者様がお悩みのRangeオブジェクトを
言葉でどんなに説明するよりも百聞は一見に如かずですので。

SUB TEST()
DIM V As Object

SET V = RANGE(“A1”)
SET V = RANGE(“A1:A2”)

END Sub

このコードをステップ実行しながらオブジェクトを実際に御覧ください。

見る方法は
オブザーバーに
V
を登録しておいてステップ実行します。

そうするとSET文を過ぎたところでVが示すオブジェクトを
確認できます。

このことがRangeオブジェクトが単一セルの場合と複数セルの場合によって
オブジェクトの持つプロパティの変化とアクセス方法を
明確に変えることの必要性を示しています。

つまり.Countを参照して1の場合と複数の場合とで
アクセス方法を変えないと、コードは成立しないのです。

これはEXCELの場合もおそらく同様ではないかと思います。

デバッグの難しいLibreと思っていましたが、このオブザーバー機能に
関しては、一つのアドバンテージじゃないかと思います。

3 Likes