Help us understand the problem. What is going on with this article?

各種小説投稿サイトのルビ記法をJavaScriptで実現する

GitHubでWeb小説の原稿を管理している8amjpと申します。

原稿は、基本的にMarkdownで書いてるんですが、厄介なのがルビの扱い。
Markdownでルビを表現することは、今のところできません。かと言って、わざわざruby要素を記述するのも面倒です。
なので、執筆時は各種小説投稿サイトで採用されているルビ記法で記述し、表示するときにJavaScriptでruby要素に変換する、という手法を取ることにしました。
その際に調べたことを書いておきます。

はじめに

HTMLでは、ルビを下記のように表記します。

<ruby>瀬尾絵子<rt>せのおえこ</rt></ruby>

ブラウザでは瀬尾絵子せのおえこという風に表示されます。
で、「瀬尾絵子」の部分をベーステキスト、「せのおえこ」の部分をルビテキストと呼びます。

各種小説投稿サイトでは、この表記を簡略化するために、

  • <ruby>に代わるベーステキストの開始記号
  • <rt></rt>に代わるルビテキストの範囲指定記号

を定義しているわけですね。

各種小説投稿サイトのルビ記法

それでは、各サイトのルールを見ていきましょう。

青空文庫

青空文庫作業マニュアル【入力編】

「4. 青空文庫注記形式」では、ルビの入力方法について以下のように定義されています。

  • 開始記号は|(全角縦棒)とする。
  • 範囲指定記号は《》(二重山括弧)とする。
  • ただし、ベーステキストが漢字の連続である場合は、開始記号を省略できる。

例: 全方位弾《ブロードキャストパケット》 |PM《プロジェクトマネージャー》

自由度は少ないですが、その分ルールはシンプルです。
ちなみに、《》(二重山括弧)をそのまま表示させることは、青空文庫ではできないらしいです。

小説家になろう/ノベラボ

ルビの振り方

小説家になろうでは、以下のように定義されています。

  • 開始記号は|(全角縦棒)または|(半角縦棒)とする。
  • 範囲指定記号は《》(二重山括弧)、()(全角丸括弧)、()(半角丸括弧)を使用できる。
  • ただし、ベーステキストが漢字の連続である場合は、開始記号を省略できる。
    • その際、範囲指定記号に()(全角丸括弧)または()(半角丸括弧)を使用した場合は、ルビテキストはカタカナまたはひらがなである必要がある。
  • 括弧内の文字をルビ扱いにしたくない場合は、括弧の直前に開始記号を付ける。

例: 強制帰還(ループバック)

だそうです。自由な分、ややこしいですね。
なおノベラボも同じルールです。縦書きなのにエライ。

カクヨム/エブリスタ/NOVEL DAYS

ルビや傍点を付ける(カクヨム記法を使う)

カクヨム記法では以下のとおり。

  • 開始記号は|(全角縦棒)または|(半角縦棒)とする。
  • 範囲指定記号は《》(二重山括弧)とする。
  • ただし、ベーステキストが漢字の連続である場合は、開始記号を省略できる。
  • 括弧内の文字をルビ扱いにしたくない場合は、括弧の直前に開始記号を付ける。

例: |《翠玉女帝》エクシエラ

ルビのルールは青空文庫とほぼ同じですが、例のように記述すると《》(二重山括弧)をそのまま表示させることもできます。
エブリスタNOVEL DAYSも同じルールです。

ハーメルン

ルビの振り方

  • 開始記号は|(半角縦棒)とする。省略不可。
  • 範囲指定記号は《》(二重山括弧)とする。

とってもシンプルです。潔い。

マグネット

  • 開始記号は|(全角縦棒)または|(半角縦棒)とする。省略不可。
  • 範囲指定記号は《》(二重山括弧)とする。

マグネットのサイトのどこにも記法は明記されていませんが、エディタで試してみた限りではこうでした。

アルファポリス

ヘルプより引用:

※ルビの振り方
サンプル:#宇宙__そら__#
上記の例の場合、「宇宙」と書かれた部分が対象のテキストで、「そら」と書かれた部分がルビになります。

……なんでこんなルールにしたの?とりあえず無視。

魔法のiらんど/野いちご

魔法のiらんど野いちごなんかは、ルビ記法は実装されていない代わりに、一部のHTML要素(タグ)が使えるそうです。
ひょっとしたら、直接ruby要素を記述することで実現できるかもしれません。(未確認)
ケータイ小説、けっこう骨太。

taskey

taskeyのルビ機能。もはや記法じゃないです。これは無理。

ルビ非対応のサイト

note時空モノガタリcomicoノベルmonogatary.comなどはルビそのものが非対応みたいです。残念。

JavaScriptでルビ機能を実装する

さて、上記に挙げた記法のうち、青空文庫/小説家になろう/カクヨムの記法通りにルビを振るJavaScript(jQuery)を作成してみます。
なお、文書全体を対象にする必要もないので、対象はarticle要素内の文字列だけにしています。

$(function(){
  $('article').each(function() {
    $(this).html(
      $(this).html()
        /* 半角または全角の縦棒以降の文字をベーステキスト、括弧内の文字をルビテキストとします。 */
        .replace(/[\|](.+?)(.+?)》/g, '<ruby>$1<rt>$2</rt></ruby>')
        .replace(/[\|](.+?)(.+?))/g, '<ruby>$1<rt>$2</rt></ruby>')
        .replace(/[\|](.+?)\((.+?)\)/g, '<ruby>$1<rt>$2</rt></ruby>')
        /* 漢字の連続の後に括弧が存在した場合、一連の漢字をベーステキスト、括弧内の文字をルビテキストとします。 */
        .replace(/([一-龠]+)(.+?)》/g, '<ruby>$1<rt>$2</rt></ruby>')
        /* ただし丸括弧内の文字はひらがなかカタカナのみを指定できます。 */
        .replace(/([一-龠]+)([ぁ-んァ-ヶ]+?))/g, '<ruby>$1<rt>$2</rt></ruby>')
        .replace(/([一-龠]+)\(([ぁ-んァ-ヶ]+?)\)/g, '<ruby>$1<rt>$2</rt></ruby>')
        /* 括弧を括弧のまま表示したい場合は、括弧の直前に縦棒を入力します。 */
        .replace(/[\|](.+?)》/g, '《$1》')
        .replace(/[\|](.+?))/g, '($1)')
        .replace(/[\|]\((.+?)\)/g, '($1)')
    );
  });
});

こんな感じですかね?もっと短くなりそうなんですけど。どうでしょう。

ちなみに、正規表現におけるひらがな・カタカナ・漢字の指定方法ですが。
ひらがなのゾーンは、「ぁあ」から始まり「ん」で終わるので、[ぁ-ん]と指定します。
一方、カタカナのゾーンは、「ァアィイ」から始まり「ヮワヰヱヲンヴヵヶ」という順番で並んでいます。[ァ-ン]だと「ヴ」とかが漏れちゃうので[ァ-ヶ]と指定します。
漢字は……なんだか定義が難しいんですけど、[一-龠]としておけば支障ない、らしいです。ご指摘があればお願いします。

サンプルあるいは宣伝

このスクリプトの適用例を宣伝しておきます。「Redmineで始める異世界人心掌握術」の冒頭部分なんですけど。

こっちがルビ変換前。
https://github.com/8novels/redmine-fantasy/blob/master/episodes/001.md

こっちがルビ変換後です。
https://8novels.github.io/redmine-fantasy/episodes/001.html

おまけ

漢字として扱いたい文字

漢字ではないけれど、漢字として扱ってほしい文字ってありますよね。例えば、「度々」の「々」、「戦場ヶ原」の「ヶ」とかですね。
こういう場合は、[一-龠々ヶ]という風に個別に追加指定すれば漢字扱いにすることができます。

傍点(圏点)

カクヨムでは、《《それ》》というように、二重山括弧ふたつで囲んだ文字に傍点(圏点)を振ることができます。これをJavaScriptで表現するには、

.replace(/《《(.+?)》》/g, '<strong>$1</strong>')

という風にstrong要素にでも変換するのがいいでしょう。
(ただし、一番最初にreplaceしないと意図した結果にならないので注意です)

それから、スタイルシートで

strong {
  -webkit-text-emphasis: filled circle black;
          text-emphasis: filled circle black;
}

とでも指定するのがいいでしょう。
……ま、Markdownなら**それ**で表記できるので別にいいんですけど。

8amjp
福井市に住むSE・プログラマ。Kindleストアで技術系異世界ファンタジー小説「Redmineで始める異世界人心掌握術」販売中。JavaScript学園コメディ「恋に落ちるコード.js」電子書籍化準備中。
https://8am.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした