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なら**それ**
で表記できるので別にいいんですけど。