msgbox の仕様

一行に長い文字列をいれると切れるようです。

s = “a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa xxx”
msgbox(s)

で、最後の xxx が表示されないようです。

環境は、Libreoffice 4.4.7 Base のマクロで試しています。
回避策はあるのでしょうか?

回答ではなく、単なる自分用のメモだ。(追記:衝撃の事実を一つ発見したので、とりあえずこの投稿は後で読めばいいです)

★最初に言っておくが、この投稿、解決策や回避策は全く示されていないし、原因もよくわからない(汗)。

便宜上、

  • ある文字列があり、その文字列には改行文字(CR, LF, CRLF)が含まれているとする。この改行文字の次の文字から次の物理行の位置に表示することを「改行」と呼ぶ。
  • 文字列を表示しようとしたところ、ウィンドウなどの幅が狭くて物理行1行に収まらず、あふれた論理行1行の一部を次の物理行の位置に表示することを「折り返し」と呼ぶ。
  • 「改行」と「折り返し」を総称して「分割」と呼ぶ。

ことにする。

  • 基本的にMsgbox関数によって表示されるダイアログは与えられる文字列の長さに応じて広がるが、その幅には上限があり、ここに折り返しの必要が出てくる。

ここで、少し話が変わる。

下準備として

の手順に従って「英語」ロケールをインストールし、ユーザーインターフェースの言語を英語にしておこう。

Writerを起動してドキュメントを新規作成。

本文に

dt

と書き込みF3を押すと、ダミーテキストが表示される。

出てきた文章は折り返されているわけだが、ここで右端が揃っていないことを確認。欧米系の言語では物理行に詰めるだけ詰めて単語の途中でぶった斬るようなことは基本的にしない。どうやっても上記の幅上限に引っかかるようなときは単純にぶった斬って分割するけど。

実際に両端を揃えたものを出版する場合には単語間のスペースを広くしたり狭めたり、線を入れたり、単語を足したりするようだ。

⇒文字列上で分割する位置を決めるためのプログラムコードが含まれる必要がある。この規則はある程度Unicode Standard Annex #14というものに従う。

  • ★上述のStarBasicのダイアログには、MS OfficeのVBAで出てくるものと違い、そういう挙動がわざわざ入っている。(個人的には嫌いだ。)

実験してみる。

ALにはアルファベットaやzが含まれる。

http://www.unicode.org/reports/tr14/#AL

EXには感嘆符(!)が含まれる。

http://www.unicode.org/reports/tr14/#EX

LB13によるとEXの前では分割できない

http://www.unicode.org/reports/tr14/#LB13

LB28によるとAL(アルファベット)とALの間は分割できない

http://www.unicode.org/reports/tr14/#LB28

ここでこんなコードを実行してみよう。

Sub Main()

Msgbox(“aaaaaaaaazaaaaaaaaazaaaaaaaaa!aaaaaaaaazaaaaaaaaazaaaaaaaaazaaaaaaaaazaaaaaaaaazaaaaaaaaa!aaaaaaaaazaaaaaaaaazaaaaaaaaazaaaaaaaaazaaaaaaaaazaaaaaaaaazaaaaaaaaazaaaaaaaaaz”) '空白・改行文字共になしアルファベットと感嘆符だけ

End Sub

というのを実行してみると、分割可能な文字列上の位置のうち、ダイアログに収まる最も後ろの点を選ぶから、
毎回感嘆符の後ろの位置(そこでしか分割できないから)と物理行に収まらなかった時の折り返しで分割されているのがわかるだろう。
そして、ふたつ目の感嘆符の後ろは80文字。!やzは10文字ごとにおいたから、最後は80文字。物理行3行目が76字で、物理行4行目が4文字

以上で前座が終了。ここから本番。

この文書を保存し、UIの言語を日本語にしよう。マクロのIDE用のウィンドウも含めて全部のウィンドウを閉じてから、この文書を読み込んだ時に反映されるぞ。☆

同じコードを実行してみると、ふたつの感嘆符で分割されるのは同じで、その後が、分割後の行もなく75文字しかなくて、物理行4行目がない。

いろいろ分割数の異なる文字列を試してみるとこのような分割位置検知用の方法をとった時、取らなかった時のウィンドウの高さ分の行数のみ表示される。(投稿修正しました)

☆現状、この環境でのみ再現するということは、欧米圏のユーザーが気づく可能性が低く、治されにくい、ということになるのかもしれない。一応UI言語の切り替えで再現性が変わるのが彼らの環境でも同じなら、修正されたことを確認する手に欠けるということがない、というのが救いになるんだろうか。

(自分にとっては)衝撃の事実

てっきり文字列結合しそびれの違いが欧米系実装と日本語実装の差にあるのだと思い込んでいた。だからそこら辺の違いを中心に調べようとしていた。でも、違う。俺は根本的な誤解をしている。

まず、確認しよう。

  • MS Office付属のVBAでMsgbox関数を実行したときに現れるダイアログの文字列を選択状態にすることはできない。
  • LibreOfficeで同様に登場させたダイアログは選択状態に出来る。

で、後者のダイアログの文字列をクリックして、ずっと矢印キー[↓]を押し続けると、そこには…。
表示されていないように見えた文字列が!

と、いうことは。「ダイアログ(あるいはVclMultiLineEdit)の高さ」を変更する部分のコードを見ていけばいい、ということだろうか

いま実験したらMSのVBAも空白では改行されるのねorz

Messagebox APIで出てくるダイアログの仕様って少しずつ変わっていたんだな。初めて知った。

Why doesn’t my MessageBox wrap at the right location?

(最初はNaruhikoさんのところに追加コメントしていたが、自分のコメントの方向があってるか自信なかったのでそっち削除してここに付け直す)

調査結果、興味深く読みました。ありがとうございます。

空白での改行がされないのは不具合とまでは言い切れませんが改善要望であってもいいかもしれませんね。個人的には、現行の仕様でもまあいいのかな、とは思いますけれども……。

ただその場合でも、改行を明示的に挟むことが必要、というドキュメンテーションがちゃんとあるかという話はありますね。ただの感想ですみません。

https://opengrok.libreoffice.org/xref/core/vcl/source/window/layout.cxx?r=832a1204#2312

調べたわけではないですが、msgboxで手で改行を入れないとウィンドウ幅で切れてしまうのは、まあ理にかなった仕様のような気がします。

(WindowsのMessageBox() APIはそういう仕様だったと記憶しています)