C# VSTO Add-inでWordのルビをHTMLのタグに変換する

HTMLの<ruby>タグを漢字のふりがなを表示するために時々使っていますが、結構便利です。
ただ、いちいちHTMLコードを書くのが面倒で、何か良い方法がないかと考えたときに、Wordが目に入りました。
Wordにもルビを振る機能があって、しかも半自動的にふりがなをつけてくれます。Wordでルビを振った文章をHTMLコードに変換する簡単なWord Add-inを作りました。

目次

完成形と使い方

画面イメージ

完成形はWordにMy Toolsというリボンタブが追加されて、中にExport<Ruby>ボタンがあります。 

WordのルビをHTMLのrubyタグに出力する


使用手順

  1. Wordでルビを振る文章を用意し、Wordのルビ機能を使ってルビを振ります。
  2. 出力したい部分を選択してExport<Ruby>を押します。
  3. これでHTMLコードがクリップボードにコピーされます。

出力されたHTMLコード

<ruby>今日<rp>(</rp><rt>きょう</rt><rp>)</rp></ruby><ruby><rp>(</rp><rt></rt><rp>)</rp></ruby><ruby>天気<rp>(</rp><rt>てんき</rt><rp>)</rp></ruby>です。 <ruby>百舌鳥<rp>(</rp><rt>もず</rt><rp>)</rp></ruby><ruby><rp>(</rp><rt></rt><rp>)</rp></ruby>んでいました。 <ruby>青空<rp>(</rp><rt>そら</rt><rp>)</rp></ruby><ruby>綺麗<rp>(</rp><rt>きれい</rt><rp>)</rp></ruby>でした。

ブラウザーでの表示効果

今日(きょう)()天気(てんき)です。 百舌鳥(もず)()んでいました。 青空(そら)綺麗(きれい)でした。

まずHTMLの<ruby>タグの使い方を知る

互換性を考慮した使い方(今回これを使う)

<ruby>今日<rp>(</rp><rt>きょう</rt><rp>)</rp></ruby>

本来は<ruby>タグは<rt>とペアで、<rp><ruby>をサポートしない古いブラウザーのためのフォールバックです。古いブラウザーでは、ふりがなが括弧の中に表示されます。

互換性を考慮せずシンプルな使い方

<ruby>今日<rt>きょう</rt></ruby>

HTMLの<ruby>タグの使い方が分かったら、Wordの形式をその通りに変換すればOKです。

そしてWordの文書構造を理解する

Characterを理解する

VSTOアドインでは、Word文書はSentence,Word,Character単位に分けられます。
これらの単位は全部Microsoft.Office.Interop.Word.Range型(Interface)として扱えます。
改行を入れたり文書の構造に合わせて出力のフォーマットを変えるのであれば、Sentence毎に処理すれば良いと思いますが、今回はシンプルに改行なしのHTMLコードを出力するだけなので、Character毎に処理します。
このCharacterは、文字通りの1文字ではなく、Rubyがある状態とない状態により区切り方が違いますので、要注意です。 

ルビがない場合のCharacterの区切り方

ルビがある場合のCharacterの区切り方


ルビのある漢字をひとかたまりにまとめてくれるので、ちょうど好都合です。

ルビと漢字のデータ構造を知る

  • ルビのあるCharacterかどうかを調べる方法
    if (cht.Fields.Count > 0) { //ルビがある場合はCharacterのFieldは1になる //同時にTextプロパティは一律 "\u0015"(否定応答)になる }
  • ルビのあるCharacterの漢字とルビの保存場所
    CharacterのFields[1].Code.Textにあります。
    cht.Fields[1].Code.Text
    形式はこんな感じです:
    //"EQ \\* jc2 \\* \"Font:游明朝\" \\* hps10 \\o\\ad(\\s\\up 9(きょう),今日)"
  • ルビのないCharacterのTextを取得する方法
    Textプロパティからとるだけでシンプルです:
    cht.Text

Wordの漢字とルビデータを元データから分離する

//"EQ \\* jc2 \\* \"Font:游明朝\" \\* hps10 \\o\\ad(\\s\\up 9(きょう),今日)" からそれぞれ漢字の今日とルビのきょうをとるには、正規表現を使います。

const string PTN_RUBY_IN_CODE = @"(?<=\()\w+(?=\))"; const string PTN_KANJI_IN_CODE = @"(?<=,)\w+(?=\)$)";

いよいよ実装する

Visual Studioでプロジェクトを作成する

  • Visual Studioを起動し、新しいプロジェクト作成を選びます。
  • テンプレートの中からWord VSTO Add-inを選びます。
    このタイプのプロジェクトが見つからない場合は、Visual StudioのインストーラーからOffice/SharePoint開発のワークロードをインストールする必要があります。
  • プロジェクト名等を決めて、.Net Framework 4.8を選択してプロジェクトを作成します。

プロジェクトにRibbonを追加する

  • ProjectメニューからAdd New Itemを選び、リストから**Ribbon(Visual Designer)**を選び追加します。
  • UIデザイナーでRibbonのNameLabelプロパティを指定します。
    この例では、My ToolsというLabelにしています。
  • リボンに一つのButtonを追加し、NameLabelプロパティを指定します。
    この例ではExport<ruby>というLabelbtnExportRubyTagとうNameにしています。

Ribbonのcsソースファイルでの準備

  • namespace usingの追加
using System.Text.RegularExpressions; using Microsoft.Office.Interop.Word;
  • 正規表現パターンの定義
//漢字とルビを取得するために正規表現 const string PTN_RUBY_IN_CODE = @"(?<=\()\w+(?=\))"; const string PTN_KANJI_IN_CODE = @"(?<=,)\w+(?=\)$)";

ボタンのClickイベントを実装する

private void btnExportRubyTag_Click(object sender, RibbonControlEventArgs e) { Range rangeSelected = Globals.ThisAddIn.Application.Selection.Range; //現在選択されている文章のRangeオブジェクトを取得する if (rangeSelected.Characters.Count == 0) {//選択されていなかったら終了 return; } StringBuilder sbRuby = new StringBuilder(); foreach (Range cht in rangeSelected.Characters) {//Characterをひとつずつみていく if (cht.Fields.Count > 0) {//ルビがある場合 sbRuby.Append("<ruby>"); //正規表現で漢字とルビをそれぞれ取得する string txtKanji = Regex.Match(cht.Fields[1].Code.Text, PTN_KANJI_IN_CODE).Value; string txtRuby = Regex.Match(cht.Fields[1].Code.Text, PTN_RUBY_IN_CODE).Value; sbRuby.Append($"{txtKanji}<rp>(</rp><rt>{txtRuby}</rt><rp>)</rp>"); sbRuby.Append("</ruby>"); } else {//ルビがない場合は文字だけ取得する sbRuby.Append(cht.Text); } } //結果をクリップボードにコピーする Clipboard.SetText(sbRuby.ToString()); }

F5を押してDebugする、問題がなければ完了

F5を押すと、Wordが起動します。先ほど作成したリボンも表示されます。

その他

Wordのルビ機能では自動的にルビを振ることができるのですが、ひらがなの部分にもルビがついてしまうようです。
例えば飛んででは、の上にだけではなく、飛んでの上にとんでが振られます。調べたらこれは仕様みたいです。
使う頻度が低いので今のところ大きな問題ではないと思いますが、よく使うようになったら何か自動的に処理できる方法を考えなければですね。

コメント

このブログの人気の投稿

C# WebView2.ExecuteScriptAsync()のいくつかの使い方とDebug方法

C# 外部ライブラリを使わずに半角→全角カタカナ変換

C# WebView2を通じてWebサーバーなしでJavaScriptからローカルファイルを読み書き