Wordでのルビ振りを一括でできるようにした話

# 概要
![process.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587871/bf601fe2-130a-89b6-8003-90067855f5bf.png)
Wordで教材を作るために、大量のテキストにルビを振りたい（ふりがなを設定したい）。しかし、Wordのルビ機能は貧弱なためほぼ手作業になり時間がかかる。そこで、ChatGPTとWord VBAを使って、ルビ振りの半自動化を目指した。

:::note info
**成果**
* ChatGPTでそこそこの精度でルビを振ることができた
* Wordの機能を使ったふりがな設定はほぼ自動化できた
:::

# 要約
* Wordでのルビ振りは精度が低く、一括処理が難しい
* ChatGPTなら自然なルビ振りが一括でできる
* Wordに貼り付けたChatGPTの出力から、自動でルビ設定するVBAのコードを書いた


# 背景
Wordのルビ振りにはいくつかの問題点があり、とても時間がかかる。教材作成のため数千字にルビを振る必要があり、時間を短縮したかった。

:::note alert
**Wordのルビ振り機能の問題点**
* カタカナ語にルビが振られる
* 送り仮名にもルビが振られる
* 正確とは限らない
* 一度に100文字程度しか処理されない ←ゆるされない
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587871/83ea6404-151c-4d00-e5b0-920795c8156c.png">
:::


# やったこと
## 1. 文章を用意する

```:プレーンテキスト
あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。
```

## 2. ChatGPTでルビを振る
ChatGPTにルビを振るように指示し、文章を入力した。

今回はChatGPT 4を使ったが、ChatGPT 3.5でもおそらくそんなに変わらないと思う。プロンプトは次のようにした。

```Text:プロンプト
入力された文章に対して、 #青空文庫形式 でルビを振ってください。
熟語には、 #熟語のルビの例 のようにまとめてルビを振ってください。
送り仮名がある場合は、 #送り仮名のある場合の例 のように、漢字部分のみにルビを振るようにしてください。
#注意事項 を守って出力してください。

#青空文庫形式
｜漢字《かんじ》

#熟語のルビの例
- 「初夏」→「｜初夏《しょか》」

#送り仮名のある場合の例
- 「越えて」→「｜越《こ》えて」

#注意事項
- すべての漢字に対してルビを振る。
- ひらがな、カタカナ、アルファベットにはルビを振らない。
- 可能であれば、意味の解釈が必要な部分では最も一般的な読み方を選ぶ。
- ルビ付きの文章のみを出力する。
- ルビを追加する以外の改変はしない。
- 読みが分からず、どうしてもルビを振れないときはそのままにしてよい。
```

```Text:入力
あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。
```

```Text:出力
あの｜イーハトーヴォ《イーハトーヴォ》のすきとおった｜風《かぜ》、｜夏《なつ》でも｜底《そこ》に｜冷《つめ》たさをもつ｜青《あお》いそら、うつくしい｜森《もり》で｜飾《かざ》られたモリーオ｜市《し》、｜郊外《こうがい》のぎらぎらひかる｜草《くさ》の｜波《なみ》。
```

「イーハトーヴォ」が漢字の熟語としてルビを振られてしまっているが、気にしないこととする。どうせルビに正解があるとは限らないので、最終的には人がチェックし、気に入らない部分は直すことになる。ここでは95%程度が自動で処理されれば御の字と考えてスルーする。

## 3. Wordに貼り付ける
ChatGPTで出力されたルビ付きのテキストをWordに貼り付ける。このように、Wordのテキストにルビを設定するわけではないので、教材づくりのプロセスは少し変える必要があった。

![スクリーンショット 2024-02-17 230828.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587871/d8a358d6-b588-0db0-eb9b-503d1d4973b7.png)


## 4. VBAでルビを設定する
貼り付けた青空文庫形式のルビ付きテキストをもとに、Wordのルビ機能でルビを設定する。文書全体を見て、青空文庫形式のルビを見つけたら、それをもとにルビを設定するコードを書いた（ChatGPTが）。

```vb:ApplyRuby.bas
Sub ApplyRubyToAll()
    Dim regex As Object
    Dim matches As Object
    Dim match As Variant
    Dim rubyText As String
    Dim mainText As String
    Dim startPos As Long, endPos As Long
    
    ' 正規表現オブジェクトの作成
    Set regex = CreateObject("VBScript.RegExp")
    With regex
        .Global = True
        .MultiLine = True
        .IgnoreCase = False
        .Pattern = "｜(.*?)《(.*?)》" ' 青空文庫形式のルビを探す正規表現
    End With
    
    ' ドキュメント内の全てのテキストに対してルビを適用
    For i = ActiveDocument.Paragraphs.Count To 1 Step -1
        Set para = ActiveDocument.Paragraphs(i)
        If regex.Test(para.Range.Text) Then
            Set matches = regex.Execute(para.Range.Text)
            ' 最後のマッチから処理を開始
            For j = matches.Count - 1 To 0 Step -1
                Set match = matches(j)
                mainText = match.SubMatches(0) ' ルビを振る対象のテキスト
                rubyText = match.SubMatches(1) ' ルビのテキスト
                startPos = match.FirstIndex + 1
                endPos = startPos + Len(match.Value) - 1
                ' ルビのテキストを含む範囲を選択
                With para.Range
                    .Start = startPos - 1
                    .End = endPos
                    .Text = mainText ' ルビ記号とルビテキストを主テキストで置換
                    .PhoneticGuide Text:=rubyText ', Alignment:=wdPhoneticGuideAlignmentOneTwoOne, Raise:=10, FontSize:=5, FontName:="BIZ UDPゴシック"
                End With
            Next j
        End If
    Next i
End Sub
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587871/fa97cb32-2d1c-0ef7-6d64-96ab2d38bcf2.png)

# 今後の課題
残る問題はいろいろあるが、手動よりはだいぶましな結果になった。

:::note warn
**問題点**
* まれに本文が改変されることがある
* カタカナにルビが振られることがある
* 生成AIを利用している（私の所属では使用が面倒）
:::

記事を書いている中で、Yahoo! JAPANがルビ振りAPIを提供していることを知った。これを使ったほうがいい気がする。

https://developer.yahoo.co.jp/webapi/jlp/furigana/v2/furigana.html

# 続編

https://qiita.com/enoz_jp/items/915ee4db96ae2097fe02