2017年7月22日土曜日

26: スプレッドシートセルから読んだりスプレッドシートセルに書いたりする、パート4

<このシリーズの、前の記事 | このシリーズの目次 | このシリーズの、次の記事>

Main body START

LibreOfficeまたはApache OpenOfficeのCalcスプレッドシートを拡張機能を通してJavaまたはマクロプログラムから操作する(読むまたは書く)方法を知る

スプレッドシートセルの文字列をどのように操作できるか?

-Hypothesizer

前は、我々は、スプレッドシートセルの文字列を、既存の文字列を消去し、新たな文字列をセットすることでセットした。

-Rebutter

確かにそうした。

-Hypothesizer

既存の文字列の任意の位置に文字列を挿入したり、既存の文字列の任意の領域をある文字列で置き換えたり、既存の文字列の任意の領域を消去したりすることもできる。

-Rebutter

それは、既存の文字列を取得して、得た文字列をJava内で操作し、既存の文字列を消去し、操作した文字列をセットすることでも行なえる。どちらが効率が良いのか?

-Hypothesizer

既存の文字列がとても長い場合、後者のほうがはるかに効率が良い。なぜだか知らないが、長い既存文字列を前者の方法で操作するのは、不思議に多くのCPUリソースを必要とする。

-Rebutter

どの程度の長さのことを言っているのか?

-Hypothesizer

数千文字だ。我々の極度に低速なコンピューターでは、1文字追加するのに約20秒かかる。

-Rebutter

そのコンピューターが極度に、極度に低速なことは知っているが、内部アルゴリズムが何か不適当ではないか?

-Hypothesizer

たぶん、そんなに長い文字列がスプレッドシートセルにセットされるとは想定されていないのだろう。長い文字列を考慮に入れれば、もっと良いアルゴリズムがあるはずだと思う。

-Rebutter

既存文字列がそれほど長くなかったらどうなのか?

-Hypothesizer

そうした場合の正確なパフォーマンスは計測していない。大量データを処理していなければ、感知できるような違いはないだろう。

-Rebutter

まあ、必要に直面したときに判断すればよいだろう。どちらにしろ、セル文字列を前者の方法で操作する必要性はあるのか?

-Hypothesizer

ああ、前者の方法が必要とされるケースはある。既存の文字列がその部分によって異なったフォーマットになっている場合、文字列全体をただ置き換えるというわけにはいかない。

-Rebutter

例えば、文字列中の1つの単語だけがイタリックという場合か?

-Hypothesizer

そうだ。もちろん、文字列全体を置き換えてフォーマットをセットしなおすことはできるが、それは面倒かもしれない。文字列全体の既存のフォーマット情報を取得して、そのフォーマットを再適用しなければならない。

-Rebutter

ふーむ、それが本当に面倒かどうかは知らないが、文字列がそれほど長くない場合、前者の方法で既存文字列を操作するのが自然そうだ。

-Hypothesizer

長いセル文字列をその部分ごとにフォーマット適用したい場合には、何か方法を考えなければならないだろう。

-Rebutter

ワードプロセッサーを扱っているわけではないので、込み入ったフォーマットが必要になるとは思わないが、文字列中の特定の単語を示すマーカーが欲しいということはあるかもしれない。

-Hypothesizer

ああ、そうかもしれない。しかし、今、そこに深入りするのはやめておこう。

-Rebutter

オーケー。

-Hypothesizer

前の記事で行なったように、セルUNOオブジェクトから、'com.sun.star.text.XText'UNOインターフェースを使って、'com.sun.star.text.XTextCursor'インスタンスを得る。UNOインターフェース、'com.sun.star.text.XTextCursor'は、'com.sun.star.text.XTextRange'のサブインターフェースであり、セルの文字列のある選択された領域を代表する。

-Rebutter

それでは、'com.sun.star.text.XTextCursor'インスタンスはただの単点カーソルではないわけだ。

-Hypothesizer

選択された領域が縮んで文字が一つも選択されていない状態になれば、この'com.sun.star.text.XTextCursor'インスタンスは単点カーソルになる。

-Rebutter

なるほど。

-Hypothesizer

メソッド、'createTextCursor'で'com.sun.star.text.XTextCursor'インスタンスを得た場合、初期状態では文字列全体が選択されている。メソッド、'createTextCursorByRange'を使えば、カーソルが文字列の先頭か終端に置かれた'com.sun.star.text.XTextCursor'インスタンスを得ることができる。

-Rebutter

おお。

-Hypothesizer

カーソルは、メソッド、'goRight'か'goLeft'によって、それぞれ右か左に移動することができる。これらのメソッドでは、カーソルを何文字分移動させるかを指定できる。

カーソルは、'gotoStart'か'gotoEnd'によって、それぞれ文字列の先頭か終端に移動することができる。

-Rebutter

文字列の領域はどのように選択できるのか?

-Hypothesizer

上記4メソッドは、選択されている領域を拡張するかどうかを指定する引数を持っている。

-Rebutter

ふーむ、察するに、ある領域を選択したい場合、その引数をオフにしてカーソルをその領域の左端に移動し、次に、その引数をオンにしてカーソルをその領域の右端まで移動すればよいわけだ。

-Hypothesizer

そう。もちろん、反対方向に、カーソルを領域の右端に位置させ、左へ拡張することでも同じことができる。

-Rebutter

なるほど。

-Hypothesizer

カーソルの状態を調整した後、'com.sun.star.text.XText'UNOインターフェースの'insertString'メソッドを呼んで文字列を挿入する。'com.sun.star.text.XTextCursor'インスタンスと挿入するべき文字列を、それぞれ第1、第2引数として渡す。. 第3引数には、選択された領域を置換するかどうかを指定する。しない場合は、新たな文字列は選択された領域の前に挿入される。

-Rebutter

文字列が挿入された後、カーソルの状態はどうなるのか?

-Hypothesizer

選択された領域が置換されるか否かにかかわらず、カーソルは、挿入された文字列の後ろに、単点カーソルとして位置する。

-Rebutter

ははあ。

-Hypothesizer

選択された領域を消去したい場合は、空文字列で領域を置換するようにメソッド、'insertString'を呼べばよい。

-Rebutter

なるほど。

-Hypothesizer

結局、前記事のコードの後に以下のコードを書いた。

   l_spreadSheetCell = l_currentSpreadSheetInXSpreadsheet.getCellByPosition (0, 8);
   l_spreadSheetCellInXPropertySet = (XPropertySet) UnoRuntime.queryInterface (XPropertySet.class, l_spreadSheetCell);
   l_spreadSheetCellInXText = (XText) UnoRuntime.queryInterface (XText.class, l_spreadSheetCell);
   l_spreadSheetCellInXPropertySet.setPropertyValue("NumberFormat", new Integer (l_textFormatIdentification));
   l_string = "0123456789";
   l_spreadSheetCell.setFormula ("");
   l_textCursor = l_spreadSheetCellInXText.createTextCursor ();
   l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
   l_textCursor = l_spreadSheetCellInXText.createTextCursorByRange (l_spreadSheetCellInXText.getEnd ());
   l_textCursor.gotoStart (false);
   l_string = "A";
   l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
   l_textCursor.goRight ( (short) 1,false);
   l_string = "B";
   l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
   l_textCursor.goRight ( (short) 1, false);
   l_textCursor.goRight ( (short) 1, true);
   l_string = "C";
   l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
   l_string = "D";
   l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
   l_textCursor.gotoEnd (false);
   l_string = "E";
   l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
   l_textCursor.goLeft ( (short) 2, false);
   l_string = "F";
   l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
   l_textCursor.goLeft ( (short) 2, false);
   l_textCursor.goLeft ( (short) 1, true);
   l_string = "G";
   l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
   l_textCursor.goLeft ( (short) 2, false);
   l_textCursor.goLeft ( (short) 1, true);
   l_string = "";
   l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
-Rebutter

カーソルを、既存文字列の終端に位置させた初期状態で取得し、文字列の先頭に移動した。

-Hypothesizer

そう。もちろん、既存文字列の先頭に位置させた初期状態で取得することもできる。上記のようにしたのは、'gotoStart'メソッドの呼び出しを実証するためだ。

-Rebutter

分かっている。

-Hypothesizer

最終的なセル文字列は"A0B1CD346G8F9E"のはずだ。

Main body END

<このシリーズの、前の記事 | このシリーズの目次 | このシリーズの、次の記事>