えー、Wordの一括ルビ振りの記事はさすがに投げっぱなし過ぎると思ったので、補足というか、コードを書きながら気づいたことなんかをちらと書いていこうかなと思いまして。
こんなことやるとこんな風になるよ、みたいな感じで。もし間違いなどありましたら、お知らせください。
~大前提(という名の余談)~
そもそもきっかけは、Officeの入っていないMacのInDesignで組版をする時に、プレーンなテキストにWindowsで、ソフトを買わずにどうやったらルビを簡単に振ることができるのか、と言うところから始まりました。(いろいろ突っ込みどころはあると思いますがスルーの方向で
まあ、ネットの海には先人たちの残したお宝が漂っていますが、作業上必要不必要な部分があるのでそれをそのまま使うわけにも行かず、ともかく、“漢字(ルビ)”この形になれば、InDesignに取り込めるコードに置き換えることができる、と言うことまでは判明しました。
そして、すでにルビが振ってあるものは、アナログ(?)ですが、ワードパッドにコピペすれば勝手に“漢字(ルビ)”になるのでそれで代用できます。
さてでは、省電力でプレーンな文章にルビを振るにはどうしたらいいでしょう。そんなところから始まったお話なのです。
前回も書きましたが、何をやっているかというと
→ 入力フォームを起動して、希望するルビの設定を入力する(※追記)
→ ルビを振りたい文章を選択する
→ 正規表現で漢字だけを選択して、 Application.Dialogs(wdDialogPhoneticGuide) でルビを振る
→ そのフィールドコードをテキストとして格納する
→ 格納したテキスト(フィールドコード)の中から、ひらがなの正規表現でルビ文字 ( ( ) で囲まれた“ひらがな”)を検索し、あったら抽出する
→ 抽出したひらがなを使用して、 .PhoneticGuide を使って、フォームで入力した配置、オフセット、サイズ、フォントで、ルビを上書きする
ということです。力技以外の何物でもないです。
コードそのものは200行に行かない程度、メイン部分で140行に行かない程度です。
ルビ振りのコードを書いていてコアになる部分といえば、親文字の検索、と思いがちですが、間違いではないですがそれだけではない、というのがワタクシの感想です。
とはいえ、この検索機能がちゃんとしていないとお話にならないのも事実なのですけどね。
ワタクシの場合、正規表現で漢字にヒットするかを判断して、ヒットしたら処理をする、という方向で組みました。
'正規表現の指定
With regKanji
.Pattern = "[一-龠々]{1,}"
.IgnoreCase = False
.Global = True
End With
~~
For Each r In rng.Characters
str = r.Text
Set Matches = regKanji.Execute(str)
If Matches.Count <> 0 Then
~~
この場合は漢字一文字にヒットします。単語単位ではありません。rng.Characters を rng.Words にすると単語単位で検索・ヒットします。{1,} はホントはいらないのですがなんとなく残してあります。
単漢字でヒットさせると漢字ごとにルビが振られるいわゆるモノルビになりますが、単語ヒットだと単語全体にルビが振られるグループルビになります。ワタクシがやりたかったのはモノルビでした。
Wordでルビを振ったことのある方ならわかると思いますが、能動的にルビを振ろうと思ったら、熟語・単語で選択してルビを振ると思います。しかし、例えば「飲み物」という単語にルビを振ろうとすると「のみもの」というルビが振られてしまい、(´・ω・`)ってなってしまうことがあると思います。さらにこの場合、ルビを文字ごとにして「み」のルビを削除するか、あるいは、最初から「飲」「物」別々にルビを振ることになります。
「ご容赦」などの場合も同じで、「ご」にも「ご」というルビが振られてしまうことがあって、後から修正することを考えると、最初から単漢字指定しておいた方が修正の負担が減るかな、と考えました。
ただ、単漢字だと「使用上」が「しよううえ」となったり、「文字」の「文」に対してルビが振られない(「ぶん」「もん」「も」など、デジタルでは判断つかない)こともあり、一長一短というかトレードオフというか。
単語単位で処理すると、おかしなルビが振られることはほぼなくなりますが、先に書いた「飲み物・ご容赦」問題が多発します。(「飲み物・ご容赦」問題って語呂がなんかいい
ちなみに、これを解決する方法もあります。
'選択範囲内でひとつめのヒット
If i < 1 Then</span>
'選択範囲を強制解除して、カーソルを選択範囲の先頭に置いて範囲指定
Selection.Collapse Direction:=wdCollapseStart
Set r2 = Selection.Range
r2.SetRange Start:=r.Start + Matches(i).FirstIndex, End:=r.Start + Matches(i).FirstIndex + Matches(i).Length
'ふたつめ以降のヒット
Else
'選択範囲を強制解除して、カーソルをふたつめ以降のヒット文字の先頭に置いて範囲指定
Selection.Collapse Direction:=wdCollapseStart
Selection.Move wdCharacter, Matches(i).FirstIndex
Set r2 = Selection.Range
getstart2 = r2.Start
r2.SetRange Start:=getstart2, End:=getstart2 + Matches(i).Length
End If
~~
「飲み物」でヒットしたMactesの中身を見ると、Item1/Item2に「飲」「物」がありましたので、それぞれを選択してルビを振るという処理を繰り返しています。「ご容赦」もこれで解決できます。
しかし、これではグループルビになってしまうのでやっぱり(´・ω・`)ってなりました。せっかく作ったのに。
ただここで思ったのは、検索ヒット機能も重要だけど、それをそのままルビ振りさせても望むようには動いてくれない ⇒ どうやってルビを振りたい親文字を範囲選択させるかが重要、ということでした(当たり前ですが
ですがそれを望む形で動かそうとすると、これが結構難しい。ワタクシはコード書きとしては素人も素人なので、ホントに何日も何日もうんうんうなってネットで探してはいろいろ試して、ようやくここにたどり着きました。なので、もっといい方法があるかもしれません。むしろ教えて下さい<(_ _)>
ちなみに、「ヒットしたら」「すでにルビがあったら」「ループしたら」など細かい条件を満たすようにするために、コード本体も If文の嵐ですし、それにともなって変数定義の嵐です(´・ω・`)
一度振られたルビ、すなわちフィールドコードの中からひらがなを抽出して、それを使って Range.PhoneticGuide でルビを振り直すのですが、ここで疑念が生まれました。
フォント名にひらがなが含まれていたら、そっちがヒットするんじゃ?
1行ずつ処理をして挙動を見ていきました。
結論としては、フィールドコードを表示していた場合は最初にヒットしたひらがな、つまりフォント名にひらがなが入っていたらそれが選択されますが、フィールドコードを表示していない場合、つまり通常では振られたルビのひらがなが選択されます。
これはどうやら、文書内(ページ内)に表示されているものが対象として処理されるようです。フィールドコードが表示されていなければ、表示されているふりがなの文字だけを対象にして、フィールドコードを表示すれば、フィールドコードの文字を対象にするようになっています。極端な話、フィールドコードにルビを振ることも可能です(まあ最終的にエラーになりますが
この辺はちゃんとしているというか、ユーザーフレンドリー(?)というか、よくできてるなぁと思います。
実は、ちょっと修正すれば“漢字(ルビ)”の形に文章を書き換えることもできます。(r.Text = r.Text & "(" & foTxt & ")" とかなんとか。なんだ、ワードパッドにコピペなんてしなくていいじゃん。
あと、ふりがなを付け替えるために、フォントや大きさ、オフセットなどの指定をフォーム入力で行うのですが、システムにインストールされているフォントの一覧を取得するのに、以下のようなコードを使っています。
~~
Const CSIDL_FONTS = 20
With CreateObject("Shell.Application").Namespace(CSIDL_FONTS)
For Each itm In .Items
rubiPanel.rubiFontBox.AddItem .GetDetailsOf(itm, 8)
Next
rubiPanel.rubiFontBox.ListIndex = 88
End With
~~
これだとインストールされた(古い)順番に格納されていくので、日本語フォントがあちらこちらに散らばってしまっています。これを昇順に並び替えたいのですが、上手いやり方がわからず、今後の課題となっています。というか誰か助けて <(_ _)>
※コメント投稿者のブログIDはブログ作成者のみに通知されます