ルビの割付を変更するFunction(Word)

ルビの割付を変更するFunction

正確に言えば、ルビの割付位置を変更した後のFieldオブジェクトのCode.Textプロパティの値を変更するFunctionです。

ルビの割付の変更

たとえば、

f:id:akashi_keirin:20190127202815j:plain

この「月面宙返」にルビを振る。

f:id:akashi_keirin:20190127202817j:plain

「ルビ」ダイアログボックスにこのように設定して、[OK]をクリックすると、

f:id:akashi_keirin:20190127202820j:plain

このように、ルビが振られる。

で、日本語入力をオフにして、[Alt] + [F9]を押すと、

f:id:akashi_keirin:20190127202824j:plain

このように、フィールドコードが表示される。

ちなみに、この場合のフィールドコードは、

EQ \* jc2 \* "Font:MS 明朝" \* hps10 \o\ad(\s\up 10(ムーンサルト),月面宙返)

となっている。

フィールドコードの解読については、

www7b.biglobe.ne.jp

コチラのサイトが非常に詳しく説明してくださっている。

ルビの割付に関わっているのは、

\* jc2 

の部分(①)と、

\ad

の部分(②)。

フィールドコードの文字列は、FieldオブジェクトのCode.Textプロパティを参照すれば取得できるので、取得した文字列のうち、①と②を書き換えて、再設定してやればよい。

ルビの割付を変更するFunctionのコード

まず、列挙体を作っておく。

リスト1 標準モジュール宣言セクション
'Enums'
Private Enum AlignCode
  acAlignCenter = 0     '中央揃え'
  acAlignDistribution1  '均等割付1'
  acAlignDistribution2  '均等割付2'
  acAlignLeft           '左揃え'
  acAlignRight          '右揃え'
End Enum

このように設定しておき、Functionの引数をAlignCode型にしておけば、引数の指定が楽かつわかりやすくなる。

次は、フィールドコード文字列点検用のFunction。

実は、均等割付絡みのフィールドコードのうち、②の方、すなわち

\ad

は、手動で「中央揃え」にすると、本来「\ac」となるはずが、省略されてしまうのである!!!!!!!!

f:id:akashi_keirin:20190127202826j:plain

f:id:akashi_keirin:20190127202830j:plain

こんなふうに手動で「中央揃え」に変更してみる。

すると、フィールドコードは、

f:id:akashi_keirin:20190127202833j:plain

ほらね。

f:id:akashi_keirin:20190127202837j:plain

こいつと比べると一目瞭然。

\o」の後がいきなり「(s\up\」になっている。

これでは非常に困る。

従って、省略を補うFunctionを作った。

スト2 標準モジュール
Private Function getRepairedFieldCodeText( _
  ByVal targetFieldCodeText) As String
  Dim ret As String
  ret = targetFieldCodeText
  Dim ar As Variant
  ar = Split(ret, "\")  '"
  'インデックスの最大値が「7」だったら、省略されていない。'
  If UBound(ar) = 7 Then GoTo Finalizer
  '省略を補う処理'
  ReDim Preserve ar(7)
  ar(7) = ar(6)
  ar(6) = ar(5)
  ar(5) = "ac("
  '手動で「中央揃え」にした後は、 ar(4) の値が"o("になる。'
  ar(4) = "o"
  ret = getAssembledFieldCodeText(ar)
Finalizer:
  getRepairedFieldCodeText = ret
End Function

Private Function getAssembledFieldCodeText( _
                   ByRef splitFieldCode As Variant) As String
  Dim i As Long
  Dim ret As String
  For i = LBound(splitFieldCode) To UBound(splitFieldCode)
    ret = ret & splitFieldCode(i) & "\"  '"
  Next
  ret = Left(ret, Len(ret) - 1)
  getAssembledFieldCodeText = ret
End Function

一旦、フィールドコード文字列を「\」をデリミタとしてSplit関数でバラしておき、必要な箇所を修正して再度組み立て直す、という処理にした。

ここまでで準備はおしまい。

あとは、メインのFunction。

リスト3 標準モジュール
Private Function getConvertedAlignmentRubyFieldCodeText( _
                   ByVal targetFieldCodeText As String, _
                   ByVal targetAlignCode As AlignCode) As String
  Dim ret As String
  ret = targetFieldCodeText
  If targetAlignCode < 0 Or _
     targetAlignCode > 4 Then GoTo Finalizer  '……(1)'
  ret = getRepairedFieldCodeText(ret)
  Dim alignSetting1 As String
  Dim alignSetting2 As String
  Select Case targetAlignCode  '……(2)'
    Case acAlignCenter
      alignSetting1 = "* jc0 ": alignSetting2 = "ac("
    Case acAlignDistribution1
      alignSetting1 = "* jc1 ": alignSetting2 = "ad("
    Case acAlignDistribution2
      alignSetting1 = "* jc2 ": alignSetting2 = "ad("
    Case acAlignLeft
      alignSetting1 = "* jc3 ": alignSetting2 = "al("
    Case acAlignRight
      alignSetting1 = "* jc4 ": alignSetting2 = "ar("
  End Select
  Dim ar As Variant  '……(3)'
  ar = Split(ret, "\")    '"
  ar(1) = alignSetting1
  ar(5) = alignSetting2
  ret = getAssembledFieldCodeText(ar)  '……(4)'
Finalizer:
  getConvertedAlignmentRubyFieldCodeText = ret
End Function

(1)の

If targetAlignCode < 0 Or _
   targetAlignCode > 4 Then GoTo Finalizer

はガード節。第2引数は列挙体にしたけれど、別に整数なら「5」でも「-3」でも渡せてしまうので、そういう予期せぬ値が渡されていたらここでシャットアウト。第1引数で渡された文字列をそのまま返すことにする。

(2)からの11行

Select Case targetAlignCode
  Case acAlignCenter
    alignSetting1 = "* jc0 ": alignSetting2 = "ac("
  Case acAlignDistribution1
    alignSetting1 = "* jc1 ": alignSetting2 = "ad("
  Case acAlignDistribution2
    alignSetting1 = "* jc2 ": alignSetting2 = "ad("
  Case acAlignLeft
    alignSetting1 = "* jc3 ": alignSetting2 = "al("
  Case acAlignRight
    alignSetting1 = "* jc4 ": alignSetting2 = "ar("
End Select

では、第2引数に応じて、均等割付の種類に応じた2箇所の文字列を変数にぶち込んでいる。

(3)からの4行

Dim ar As Variant
ar = Split(ret, "\")  '"
ar(1) = alignSetting1
ar(5) = alignSetting2

では、Split関数で一旦フィールドコード文字列をバラし、インデックス「1」と「5」の要素を書き換える。

あとは(4)の

ret = getAssembledFieldCodeText(ar)

で、リスト2getAssembledFieldCodeTextメソッドを用いて、再びフィールドコード文字列を組み立て直しておしまい。

使ってみる

次のコードで実験。

リスト4 標準モジュール
Public Sub test01()
  Dim targetField As Field
  For Each targetField In Selection.Fields
    With targetField
      If .Type = wdFieldFormula And _
         (InStr(1, .Code.Text, "\s\up") > 0 Or _
          InStr(1, .Code.Text, "\s\do") > 0) Then  '……(5)'
        .Code.Text = getConvertedAlignmentRubyFieldCodeText( _
                        .Code.Text, acAlignLeft)    '……(*)'
      End If
    End With
  Next
End Sub

選択範囲のFieldオブジェクトを総当たりにする方式。

したがって、(5)の

If .Type = wdFieldFormula And _
   (InStr(1, .Code.Text, "\s\up") > 0 Or _
    InStr(1, .Code.Text, "\s\do") > 0) Then

で、ルビのためのフィールドなのかどうかを判定する。

ルビ用のフィールドコードの特徴は、「\s\up」(上付き)か(手動で設定できないからめったに見かけないけど)「\s\do」(下付き)のどちらかが含まれていることなので、このような条件式にした。

実行結果

(*)のところでgetConvertedAlignmentRubyFieldCodeTextメソッドに渡した第2引数がacAlignLeftなので、

f:id:akashi_keirin:20190127202840j:plain

当然こうなる。

(*)を

.Code.Text = getConvertedAlignmentRubyFieldCodeText( _
               .Code.Text, acAlignRight)

に変えると、

f:id:akashi_keirin:20190127202843j:plain

こうなって、

.Code.Text = getConvertedAlignmentRubyFieldCodeText( _
               .Code.Text, acAlignCenter)

こうすると、

f:id:akashi_keirin:20190127202846j:plain

こうなる。

おわりに

Wordのルビ周りは、フィールドコードが絡むこともあって、なかなか気軽には手を出しにくい領域だったが、ワードの理解シリーズ様のおかげで、だいぶ理解が進んだと思う。

ここまで下準備ができていれば、ルビのフォントを変えたり、サイズを変えたりするぐらいなら楽勝です。

参考

コチラもどうぞ。

akashi-keirin.hatenablog.com

akashi-keirin.hatenablog.com

akashi-keirin.hatenablog.com

akashi-keirin.hatenablog.com