2020年2月20日木曜日

表内での文字列置換の不具合を回避したこと

※以下のコードは Notes 9.0.1 FP8 と Notes 11.0.0 で確認したものです

リッチテキストフィールドに次のような 3 行 x 3 列の表だけあります。セル内にはテキストだけあり、テキストに文字の装飾は無い(ひとつのセルにひとつのテキストランがある)ものとします。

test (1)test (2)test (3)
test (4)test (5)test (6)
test (7)test (8)test (9)

この表には 9 つのセルがありますが、この表の特定のセルにある文字列を対象に、文字を置換します。

特定のセルは1つとは限らず、複数のセルに跨る場合もあります。複数のセルの場合、それらは連続しているものとします。

といった、非常に特殊な件に対応するため、ヘルプにある SetPositionAtEnd メソッドと SetEnd メソッドのサンプルコードを参考にしながら次のコードを書きました。

Dim ss As NotesSession
Dim doc As NotesDocument
Dim body As NotesRichTextItem
Dim nav As NotesRichTextNavigator
Dim range As NotesRichTextRange
Const elm = RTELEM_TYPE_TEXTRUN
Const firstRun = 3
Const lastRun = 6
Const findString = "test"
Const replString = "prod"
Sub Initialize
 Set ss = New NotesSession
 Set doc = ss.Currentdatabase.Unprocesseddocuments.Getfirstdocument()
 Set body = doc.Getfirstitem( "Body" )
 Set nav = body.Createnavigator
 
 If nav.Findnthelement( elm , firstRun ) Then
  Set range = body.Createrange()
  Call range.Setbegin( nav )
  If nav.Findnthelement( elm, lastRun ) Then
   Call nav.SetPositionAtEnd( nav )
   Call range.Setend( nav )
  End If
  Call range.FindAndReplace( findString, replString, RT_REPL_ALL + RT_FIND_CASEINSENSITIVE)
  Call body.Update
 End If
 Call doc.save( True, False )
End Sub

ビューでフォーカスしている文書に対してこのコードを実行してみたところ、テキストランの範囲(今回の条件下では、テキストランの位置はセルの位置と等しいため、3 ~ 6 番目のセルを指すことと同じです)にある 3 ~ 5 番目のセルにある値が FindAndReplace メソッドによって正しく置換されるのですが、最後の(6 番目の)セルの値が削除されてしまうことに気付きました。

test (1)test (2)prod (3)
prod (4)prod (5)
test (7)test (8)test (9)

この問題をサポートへ問い合わせたところ、不具合であると報告がありました。※TSAOBLXCQL で追跡できます

またこのコードの 21 行目にある Call nav.SetPositionAtEnd( nav ) の行を削除することで、範囲の最後にあるセルの値が削除される問題がなくなることを、併せて教えていただきました。

ところが、21行目を削除してみたのですが、指定する範囲を 3 ~ 6 とした場合、FindAndReplace で置換される範囲は 3 ~5 番目が対象となり、範囲の最後にあるセルの値が置換されずにそのまま残ります。範囲がセル 1 つ分少なくなったようです。

SetPositionAtEnd を削除したからでしょうか。理由はともかく範囲の最後に 1 を加えてみることにしました。

次のようにコードを書き替えました。※Initialize 以外の部分は同じなので省略

Sub Initialize
 Set ss = New NotesSession
 Set doc = ss.Currentdatabase.Unprocesseddocuments.Getfirstdocument()
 Set body = doc.Getfirstitem( "Body" )
 Set nav = body.Createnavigator
 
 If nav.Findnthelement( elm , firstRun ) Then
  Set range = body.Createrange()
  Call range.Setbegin( nav )
  If nav.Findnthelement( elm, lastRun + 1 ) Then
   Call range.Setend( nav )
  End If
  Call range.FindAndReplace( findString, replString, RT_REPL_ALL + RT_FIND_CASEINSENSITIVE)
  Call body.Update
 End If
 Call doc.save( True, False )
End Sub

こうして指定したセルの範囲にある文字をすべて置換できるようになりました。

test (1)test (2)prod (3)
prod (4)prod (5)prod (6)
test (7)test (8)test (9)

ちなみに、今回の条件の下では定数 elm の値を RTELEM_TYPE_TEXTPARAGRAPH (テキスト段落)に変えても同様の結果が得られました。

0 件のコメント:

コメントを投稿