ヘブライ文字混在テキストを作ろう

Word に泣かされた人のための Unicode 双方向テキスト入門

前書き

本ページは 言語学な人々 Annex Advent Calendar 2024(別館) のエントリー記事です。執筆者の高橋 はヘブライ語をはじめとするセム諸語、エチオピア少数言語のフィールド調査デジタル・ヒューマニティーズの活用、ということで諸分野を横断的にうろうろしています。よろしくお願いします。

キリスト教会歴は日没から日没までが「一日」ですから、私たちの暦では、クリスマスは 24 日日没に始まり、25 日日没に終わります。本日がアドベントカレンダーの最終日ということで、ひっそり書きます。

なお、ユダヤ暦では本日 25 日夜から、1 月 2 日日没までの 8 日間が חַנֻכָּה(古典翻字 ḥanukkāh)「神殿奉献記念祭/宮きよめの祭り」になります。旧約聖書の「続編」であるマカバイ記に由来するお祭りで(一マカ4:59、cf. ヨハ10:22)、前 2 世紀にセレウコス朝シリア帝国からエルサレム神殿を奪還し、この時ろうそくの灯火が消えることがなかったということで、この期間は油をたっぷり使った料理やお菓子を食べます。

緊迫する中東情勢において、皆に慰めがあるよう祈りつつ。


Unicode 双方向テキスト入門

1. はじめに

Microsoft® Word には段落の「文字列の方向」を切り替えるボタンがあります。もしメニューバーになければ「Word のオプション」からツールバーに追加することもできます(図 1a)。

図 1a:Word の「文字列の方向」ボタン

さて、たとえば図 1b のように、番号+ヘブライ文字(אלימפיאדה /olimpiada/「オリンピック」)と入力します。日本語環境でなら、ヘブライ文字はきちんと右から左(←)に流れつつ、文字列全体は左から右(→)の方向に流れるでしょう。しかし、これを「ヘブライ語の文書」として考えるなら、文字列全体が右から左(←)に流れてほしい。そこで、Word 上で「文字列の方向」を切り替えます。

図 1b:段落の「文字列の方向」を切り替え

しかし、図 1b の結果は好ましいものではありません。行頭に奇妙なスペースがあり、最初のヘブライ文字 א と括弧の間のスペースが消えてしまっています。

Word に限らず、何らかのアプリケーション上でヘブライ文字を入力していると「好ましい結果にならない」ことが多々あります。また、この件に関する日本語の情報も極めて少ない状況です。そこで、本記事は次のことについて述べます。

  1. ざっくりと Unicode 双方向アルゴリズムを概観します。そうすれば「正しい結果なのか、そうでないのか」、言い換えれば「テキスト作成者の責任なのか、Word(アプリケーション)の責任なのか」ということで、問題を切り分けることができます。
  2. Word(アプリケーション)がうまく表示してくれなかったとしても、制御する方法を検討します。

以上 2 点、見ていきましょう。

2. 文字の方向性

まず、Unicode では個々の文字ごとに固有の「方向性」を持っている、ということをざっくりと押さえておきましょう。文字の方向性には大きく「強い方向性」「弱い方向性」「方向性に中立」の 3 種類があります。

強い方向性(本記事では → / ← で表す)
ラテン文字、キリル文字、ギリシア文字、日本語仮名や漢字などは左から右(→)、アラビア文字やヘブライ文字は右から左(←)、のように決まっています。
弱い方向性(本記事では ⇢ / ⇠ で表す)
いわゆる数字(0、1、……、9)が該当します。
中立の方向性(本記事では * で表す)
空白類、括弧類 ( ... )、[ ... ]、約物類が該当します。

※もっと詳しく知りたい方は「Unicode Character Database(@SuikaWiki)」「双方向性(BIDI)(@アンテナハウス株式会社)」を参照してください。

以下、順に確認します。

2.1. 強い方向性

強い方向性を持つ文字(本記事では単に「強い文字」と呼ぶことにします)は、文字列の中で同じ方向性を持つ部分文字列を作ります。これをラン(run)と呼びます。ひとまず例 2.1 を見てください。

論理順 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16]
    א ו ל י מ פ י א ד ה
方向  
実現方向 [ → → ] [ ← ← ]
表示順
[1]
[2]
[3]
[4]
[5]
[6]
[7]
א
[8]
ו
[9]
ל
[10]
י
[11]
מ
[12]
פ
[13]
י
[14]
א
[15]
ד
[16]
ה
HTML による(論理順での)入力例
‭オリンピックאלימפיאדה‬
あなたのブラウザではどう表示されているでしょうか
オリンピックאלימפיאדה
例 2.1

この例は、カタカナで「オリンピック」と入力した後に、ヘブライ文字で אלימפיאדה(オリンピック)と入力したことを表しています。文字列の個々の文字は入力順に保存されていますので、これを論理順(logical order)と呼び、本記事では個々の文字の順番を [数字] のように表すことにします。

カタカナは左から右(→)の強い方向性を持ち、ひとかたまりになって左から右(→)のランを作ります。これを実現方向と呼び、本記事では [→→] のように表すことにします。一方、右から左(←)の強い方向性を持つヘブライ文字も、ひとかたまりになって右から左(←)のラン [←←] を作ります。

こうして異なる方向のランが 2 つできましたが、ランそのものの方向(最初の方向)は、最初のランの方向が決めます。しかし、Word の「文字列の方向」ボタンのように、外部から「最初の方向」が与えられることもあります。本記事では「最初の方向」を論理順の [0] で表すことにします。

そして、実際に表示されるはずの文字の順番を表示順と呼びます。

2.2. 弱い方向性

弱い方向性を持つ文字(本記事では単に「弱い文字」と呼ぶことにします))は、ランの中に別のランを埋め込みます。典型的には数字です。

論理順 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20]
    א ו ל י מ פ י א ד ה 2 0 2 4
方向  
実現方向 [ → → ] [ ← [ → → ] ]
表示順
[1]
[2]
[3]
[4]
[5]
[6]
[7]
א
[8]
ו
[9]
ל
[10]
י
[11]
מ
[12]
פ
[13]
י
[14]
א
[15]
ד
[16]
ה
[17]
2
[18]
0
[19]
2
[20]
4
HTML による(論理順での)入力例
‭オリンピックאלימפיאדה2024‬
あなたのブラウザではどう表示されているでしょうか
オリンピックאלימפיאדה2024
例 2.2

例 2.2 のように、ヘブライ文字ヘブライ語の正書法では数字部分は左から右(⇢)の方向に切り替え、終わったらもとの方向(←)に戻ります。このように「後でもとの方向に戻る」ための仕組みが「ランの埋め込み」です。

2.3. 中立の方向性

固有の方向性を持たない文字もあります。これを「中立の方向性を持つ文字」と言い換えておきます(かつ、本記事では単に「中立文字」と呼ぶことにします)。典型的には空白類、括弧類、約物類です。これに属する文字は、次のルールで方向が決まります。

  • 同じ方向の「強い文字」に挟まれた時は、その方向になります。
  • 異なる方向の「強い文字」に挟まれた時は、上位のランの方向をとります。
  • 開き括弧と閉じ括弧のペアが存在する時は、開き括弧の方向が閉じ括弧にも適用されます。

次の例 2.3 において、中立文字が置かれた文脈と、方向が決まっていく様子を確認してください。

論理順 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21]
    א <SPC> ה <SPC> ח <SPC> ע ג ר ו נ י י ם
方向   * * * * *
実現方向 [ → → ] [ ← ← ] [ → → ] [ ← ← ] [ → ]
表示順
[1]
[2]
[3]
א
[4]
<SPC>
[5]
ה
[6]
<SPC>
[7]
ח
[8]
<SPC>
[9]
ע
[10]
[11]
[12]
[13]
[14]
ג
[15]
ר
[16]
ו
[17]
נ
[18]
י
[19]
י
[20]
ם
[21]
HTML による(論理順での)入力例
‭喉音א ה ח ע(つまりגרוניים)‬
あなたのブラウザではどう表示されているでしょうか
喉音א ה ח ע(つまりגרוניים)
例 2.3

3. 文字列の方向を制御する

3.1. 強い方向性を持つだけの見えない文字を書き入れる

前節で見てきた強い文字、弱い文字、中立文字の 3 つの中で、予想しない結果になりがちなのは中立文字、すなわち空白類、括弧類です。置かれた文脈によって方向が変わるからです。

そうであれば、中立文字はなるべく強い文字で挟むように文章を書けば良い……のですが、なかなかそうはいきません。しかし、発想はこれでよろしい。次に挙げるように、Unicode には強い方向性を持つ「見えない文字」が用意されています。これで中立文字を挟んでやれば良い。

名称 略称 XML文字参照
Left-to-Right Mark <LRM> &#x200E;
Right-to-Left Mark <RLM> &#x200F;

たとえば、次の例 3.1aは、日本語による文法解説の中で「א ה ח ע」のように、個々の文字をアレフベート順に左から右(→)に書こうとしています。しかし、普通に書くと「א ה ח ע」のように、ヘブライ文字の部分が右から左(←)に表示されてしまいます。そこで、ヘブライ文字の直後、スペースの直前に <LRM> を挟み込むことで、右から左(←)のランを逐一断ち切っています。

論理順 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23] [24]
    א <LRM> <SPC> ה <LRM> <SPC> ח <LRM> <SPC> ע ג ר ו נ י י ם
方向   * * * * *
実現方向 [ → → ] [ ← ] [ → → ] [ ← ] [ → → ] [ ← ] [ → → ] [ ← ] [ → → ] [ ← ← ] [ → ]
表示順
[1]
[2]
[3]
א
[4]
<LRM>
[5]
<SPC>
[6]
ה
[7]
<LRM>
[8]
<SPC>
[9]
ח
[10]
<LRM>
[11]
<SPC>
[12]
ע
[13]
[14]
[15]
[16]
[17]
ג
[18]
ר
[19]
ו
[20]
נ
[21]
י
[22]
י
[23]
ם
[24]
HTML による(論理順での)入力例
‭喉音א&#x200E; ה&#x200E; ח&#x200E; ע(つまりגרוניים)‬
あなたのブラウザではどう表示されているでしょうか
喉音א‎ ה‎ ח‎ ע(つまりגרוניים)
例 3.1a

弱い文字の前に <LRM><RLM> を入れると、別のランの中に埋め込みをすることになります。試しに、先述の例 2.2 の数字列 ‘2024’ の前に <LRM> を置いてみたのが例 3.1 です。

論理順 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21]
    א ו ל י מ פ י א ד ה <LRM> 2 0 2 4
方向  
実現方向 [ → → ] [ ← ← ] [ → [ → → ] ]
表示順
[1]
[2]
[3]
[4]
[5]
[6]
[7]
א
[8]
ו
[9]
ל
[10]
י
[11]
מ
[12]
פ
[13]
י
[14]
א
[15]
ד
[16]
ה
[17]
<LRM>
[18]
2
[19]
0
[20]
2
[21]
4
HTML による(論理順での)入力例
‭オリンピックאלימפיאדה&#x200E;2024
あなたのブラウザではどう表示されているでしょうか
オリンピックאלימפיאדה‎2024
例 3.1b

例 3.1c は、実用上は無意味ですが、頭の体操です。ヘブライ文字列「א ה ח ע」の真ん中だけに <LRM> を挟み込むとどうなるでしょうか。

論理順 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22]
    א <SPC> ה <SPC> <LRM> ח <SPC> ע ג ר ו נ י י ם
方向   * * * * *
実現方向 [ → → ] [ ← ← ] [ → → ] [ ← ← ] [ → → ] [ ← ← ] [ → ]
表示順
[1]
[2]
[3]
א
[4]
<SPC>
[5]
ה
[6]
<SPC>
[7]
<LRM>
[8]
ח
[9]
<SPC>
[10]
ע
[11]
[12]
[13]
[14]
[15]
ג
[16]
ר
[17]
ו
[18]
נ
[19]
י
[20]
י
[21]
ם
[22]
HTML による(論理順での)入力例
‭喉音א ה &#x200E;ח ע(つまりגרוניים)‬
あなたのブラウザではどう表示されているでしょうか
喉音א ה ‎ח ע(つまりגרוניים)
例 3.1c

次の例 3.1dは、日本語とヘブライ語の語彙リストを作るめ、番号・ヘブライ文字表記・ラテン文字音訳・日本語訳をこの順番で入力しています。番号(中立文字と弱い文字)がヘブライ文字に引き摺られて右から左(←)の開始になっていますが、これはこれで特に問題ありません。

論理順 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20]
    ( 1 2 ) <SPC> מ ל ך <SPC> ( m ɛ l ɛ k h )
方向   * * * * * * * *
実現方向 [ ← [ → → ] ← ] [ → → ] [ ← ← ] [ → ] [ ← ]
表示順
[1]
(
[2]
1
[3]
2
[4]
)
[5]
<SPC>
[6]
מ
[7]
ל
[8]
ך
[9]
<SPC>
[10]
(
[11]
m
[12]
ɛ
[13]
l
[14]
ɛ
[15]
k
[16]
h
[17]
)
[18]
[19]
[20]
HTML による(論理順での)入力例
‭(12) מלך (mɛlɛḵ)「王」‬
あなたのブラウザではどう表示されているでしょうか
(12) מלך (mɛlɛkh)「王」
例 3.1d

試しに、例 3.1e のように <LRM> を書き入れてみます。

論理順 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21]
    ( 1 2 ) <SPC> מ ל ך <SPC> <LRM> ( m ɛ l ɛ k h )
方向   * * * * * * * *
実現方向 [ ← [ → → ] ← ] [ → → ]
表示順
[1]
(
[2]
1
[3]
2
[4]
)
[5]
<SPC>
[6]
מ
[7]
ל
[8]
ך
[9]
<SPC>
[10]
<LRM>
[11]
(
[12]
m
[13]
ɛ
[14]
l
[15]
ɛ
[16]
k
[17]
h
[18]
)
[19]
[20]
[21]
HTML による(論理順での)入力例
‭(12) מלך &#x200E;(mɛlɛḵ)「王」‬
あなたのブラウザではどう表示されているでしょうか
(12) מלך ‎(mɛlɛkh)「王」
例 3.1e

3.2. 方向を強制したランを埋め込む

緊急事態につき、とりあえずすべての文字の方向を強制的に上書きする、ということが可能です。次に挙げる不可視文字を使うと、<PDF> が出現するまで、すべての文字の実現方向を強制したランの埋め込みを行います(埋め込みであることに注意してください)。原則として使用を避けるべきものです

名称 略称 XML文字参照
Left-to-Right Override <LRO> &#x200D;
Right-to-Left Override <RLO> &#x200E;
Pop Directional Formatting <PDF> &#x202C;

なお、本記事ではこの不可視文字をそれぞれ ⇥、⇤、‖ のように表しています。

次の例 3.2a では、右から左(←)のランを作るべきヘブライ文字の前に <LRO> を書き入れ、その後のすべての文字の実現方向を左から右(→)に強制上書きしました。<PDF> を使っていないため、文字列の最後までそうなります。

論理順 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22]
    <LRO> א <SPC> ה <SPC> ח <SPC> ע ג ר ו נ י י ם
方向   * * * * *
実現方向 [ → [ → [ → → ] ] ]
表示順
[1]
[2]
[3]
<LRO>
[4]
א
[5]
<SPC>
[6]
ה
[7]
<SPC>
[8]
ח
[9]
<SPC>
[10]
ע
[11]
[12]
[13]
[14]
[15]
ג
[16]
ר
[17]
ו
[18]
נ
[19]
י
[20]
י
[21]
ם
[22]
HTML による(論理順での)入力例
‭喉音&#x202D;א ה ח ע(つまりגרוניים)‬
あなたのブラウザではどう表示されているでしょうか
喉音‭א ה ח ע(つまりגרוניים)
例 3.2a

もっとも、このままでは次に登場するヘブライ文字列「גרוניים」まで「‭גרוניים‬」のように左から右(→)になってしまいますから、適当な所に <PDF> を記入して強制上書きを終了したのが例 3.2bです。

論理順 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23]
    <LRO> א <SPC> ה <SPC> ח <SPC> ע <PDF> ג ר ו נ י י ם
方向   * * * * *
実現方向 [ → [ → [ → → ] → ] → ] [ ← ← ] [ → ]
表示順
[1]
[2]
[3]
<LRO>
[4]
א
[5]
<SPC>
[6]
ה
[7]
<SPC>
[8]
ח
[9]
<SPC>
[10]
ע
[11]
<PDF>
[12]
[13]
[14]
[15]
[16]
ג
[17]
ר
[18]
ו
[19]
נ
[20]
י
[21]
י
[22]
ם
[23]
HTML による(論理順での)入力例
‭喉音&#x202D;א ה ח ע&#x202C;(つまりגרוניים)‬
あなたのブラウザではどう表示されているでしょうか
‭喉音א ה ח ע‬(つまりגרוניים)
例 3.2b

<LRO><RLO> による強制上書きは埋め込みであるため、予想しにくい表示順になることがあります。頭の体操として例 3.2c3.2d を確認してください。

論理順 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22]
    א <SPC> ה <LRO> <SPC> ח <SPC> ע ג ר ו נ י י ם
方向   * * * * *
実現方向 [ → [ ← [ → [ → → ] ] ] ]
表示順
[1]
[2]
[3]
א
[4]
<SPC>
[5]
ה
[6]
<LRO>
[7]
<SPC>
[8]
ח
[9]
<SPC>
[10]
ע
[11]
[12]
[13]
[14]
[15]
ג
[16]
ר
[17]
ו
[18]
נ
[19]
י
[20]
י
[21]
ם
[22]
HTML による(論理順での)入力例
‭喉音א ה&#x202D; ח ע(つまりגרוניים)‬
あなたのブラウザではどう表示されているでしょうか
喉音א ה‭ ח ע(つまりגרוניים)
例 3.2c
論理順 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23]
    א <SPC> ה <LRO> <SPC> ח <SPC> ע <PDF> ג ר ו נ י י ם
方向   * * * * *
実現方向 [ → → ] [ ← [ → [ → → ] → ] ] [ → → ] [ ← ← ] [ → ]
表示順
[1]
[2]
[3]
א
[4]
<SPC>
[5]
ה
[6]
<LRO>
[7]
<SPC>
[8]
ח
[9]
<SPC>
[10]
ע
[11]
<PDF>
[12]
[13]
[14]
[15]
[16]
ג
[17]
ר
[18]
ו
[19]
נ
[20]
י
[21]
י
[22]
ם
[23]
HTML による(論理順での)入力例
‭喉音א ה&#x202D; ח ע&#x202C;(つまりגרוניים)‬
あなたのブラウザではどう表示されているでしょうか
喉音א ה‭ ח ע‬(つまりגרוניים)
例 3.2d

3.3. 方向を強制しないランを埋め込む

方向の強制はしないものの、特定の部分文字列を埋め込みにしたい、ということもありえます。弱い文字によるランと同様に「後でもとの方向に戻る」ことを念頭に、部分的に方向を変えたい時などです。ただし、これも原則として使用を避けるべきものです

名称 略称 XML文字参照
Left-to-Right Embedding <LRE> &#x200A;
Right-to-Left Embedding <RLE> &#x200B;
Pop Directional Formatting <PDF> &#x202C;

前節同様、本記事ではこの不可視文字をそれぞれ ⇥、⇤、‖ のように表しています。

次の例 3.3a では、最初の 2 文字「喉音」の後ろをすべて埋め込みにしています。結果的には、埋め込まない場合の表示順と変わりません。

論理順 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22]
    <LRE> א <SPC> ה <SPC> ח <SPC> ע ג ר ו נ י י ם
方向   * * * * *
実現方向 [ → [ → [ ← ← ] [ ← ← ] → ] ]
表示順
[1]
[2]
[3]
<LRE>
[4]
א
[5]
<SPC>
[6]
ה
[7]
<SPC>
[8]
ח
[9]
<SPC>
[10]
ע
[11]
[12]
[13]
[14]
[15]
ג
[16]
ר
[17]
ו
[18]
נ
[19]
י
[20]
י
[21]
ם
[22]
HTML による(論理順での)入力例
‭喉音&#x202A;א ה ח ע(つまりגרוניים)‬
あなたのブラウザではどう表示されているでしょうか
喉音‪א ה ח ע(つまりגרוניים)
例 3.3a

<PDF> で埋め込み終了を明示してみますが、次の例 3.3b も表示順は変わりません。

論理順 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23]
    <LRE> א <SPC> ה <SPC> ח <SPC> ע <PDF> ג ר ו נ י י ם
方向   * * * * *
実現方向 [ → [ → [ ← ← ] ] [ ← ← ] → ]
表示順
[1]
[2]
[3]
<LRE>
[4]
א
[5]
<SPC>
[6]
ה
[7]
<SPC>
[8]
ח
[9]
<SPC>
[10]
ע
[11]
<PDF>
[12]
[13]
[14]
[15]
[16]
ג
[17]
ר
[18]
ו
[19]
נ
[20]
י
[21]
י
[22]
ם
[23]
HTML による(論理順での)入力例
‭喉音&#x202A;א ה ח ע&#x202C;(つまりגרוניים)‬
あなたのブラウザではどう表示されているでしょうか
喉音‪א ה ח ע‬(つまりגרוניים)
例 3.3b

それでは試しに、例 3.3c のようにヘブライ文字列の途中から埋め込みを開始してみます。すると、右から左(←)のランの中に埋め込みを行ったため、例 3.2c と同じように、予想しにくい表示順になります。

論理順 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22]
    א <SPC> ה <LRE> <SPC> ח <SPC> ע ג ר ו נ י י ם
方向   * * * * *
実現方向 [ → [ ← [ → [ ← ← ] [ ← ← ] → ] ] ]
表示順
[1]
[2]
[3]
א
[4]
<SPC>
[5]
ה
[6]
<LRE>
[7]
<SPC>
[8]
ח
[9]
<SPC>
[10]
ע
[11]
[12]
[13]
[14]
[15]
ג
[16]
ר
[17]
ו
[18]
נ
[19]
י
[20]
י
[21]
ם
[22]
HTML による(論理順での)入力例
‭喉音א ה&#x202A; ח ע(つまりגרוניים)‬
あなたのブラウザではどう表示されているでしょうか
喉音א ה‪ ח ע(つまりגרוניים)
例 3.3c

ランの埋め込みを行う時は、<PDF> による終了を忘れないようにすべきです。例 3.3d は頭の体操です。

論理順 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23]
    א <SPC> ה <LRE> <SPC> ח <SPC> ע <PDF> ג ר ו נ י י ם
方向   * * * * *
実現方向 [ → [ ← [ → [ ← ← ] ] ] [ ← ← ] → ]
表示順
[1]
[2]
[3]
א
[4]
<SPC>
[5]
ה
[6]
<LRE>
[7]
<SPC>
[8]
ח
[9]
<SPC>
[10]
ע
[11]
<PDF>
[12]
[13]
[14]
[15]
[16]
ג
[17]
ר
[18]
ו
[19]
נ
[20]
י
[21]
י
[22]
ם
[23]
HTML による(論理順での)入力例
‭喉音א ה&#x202A; ח ע&#x202C;(つまりגרוניים)‬
あなたのブラウザではどう表示されているでしょうか
喉音א ה‪ ח ע‬(つまりגרוניים)
例 3.3d

3.4. 新たなランを作る

ランの埋め込み(<LRO><RLO><LRE><RLE><PDF>)による方向の制御は、文脈に応じた柔軟な表示を期待されたものでした。ところが、文脈の影響が大きすぎ、かえって予想しにくい結果をもたらすことが多々ありました。

そこで、Unicode 6.3(2013 年)で次に挙げる不可視文字が追加されました。これらは強い文字のように、新たな(独立した)ランを作るものです。2024 年現在はこれらの使用が推奨されていますが、アプリケーションの対応状況には注意してください。すでに古びたものですが、Microsoft® Word 2016 は対応しておらず、また、macOS Monterey(12.4)の文字ビューアにもこれらの不可視文字は収録されていません。

名称 略称 XML文字参照
Left-to-Right Isolate <LRI> &#x2066;
Right-to-Left Isolate <RLI> &#x2067;
First Strong Isolate <FSI> &#x2068;
Pop Directional Isolate <PDI> &#x2069;

例 3.4a を見てください。<LRI> が埋め込みではなく、新たなランを作っています。

論理順 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23]
    א <SPC> ה <LRI> <SPC> ח <SPC> ע <PDI> ג ר ו נ י י ם
方向   * * * * *
実現方向 [ → → ] [ ← ← ] [ → [ → ] [ ← ← ] ← ] [ → → ] [ ← ← ] [ → ]
表示順
[1]
[2]
[3]
א
[4]
<SPC>
[5]
ה
[6]
<LRI>
[7]
<SPC>
[8]
ח
[9]
<SPC>
[10]
ע
[11]
<PDI>
[12]
[13]
[14]
[15]
[16]
ג
[17]
ר
[18]
ו
[19]
נ
[20]
י
[21]
י
[22]
ם
[23]
HTML による(論理順での)入力例
‭喉音א ה&#x2066; ח ע&#x2069;(つまりגרוניים)‬
あなたのブラウザではどう表示されているでしょうか
喉音א ה⁦ ח ע⁩(つまりגרוניים)
例 3.4a

例 3.4b<RLI> を書き入れた時の様子です。

論理順 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23]
    א <SPC> ה <RLI> <SPC> ח <SPC> ע <PDI> ג ר ו נ י י ם
方向   * * * * *
実現方向 [ → → ] [ ← ← ] [ → [ ← ← ] ← ] [ → → ] [ ← ← ] [ → ]
表示順
[1]
[2]
[3]
א
[4]
<SPC>
[5]
ה
[6]
<RLI>
[7]
<SPC>
[8]
ח
[9]
<SPC>
[10]
ע
[11]
<PDI>
[12]
[13]
[14]
[15]
[16]
ג
[17]
ר
[18]
ו
[19]
נ
[20]
י
[21]
י
[22]
ם
[23]
HTML による(論理順での)入力例
‭喉音א ה&#x2067; ח ע&#x2069;(つまりגרוניים)‬
あなたのブラウザではどう表示されているでしょうか
喉音א ה⁧ ח ע⁩(つまりגרוניים)
例 3.4b

4. 不具合対策

ここまで Unicode 双方向アルゴリズムをざっくりと練習してきました。これで、Word に立ち向かう武器を手に入れたことになります!

すでに古びたバージョンではありますが、Microsoft® Word 2016(Mac 版も同様)は、中立文字であるはずの空白類や括弧類を、常に左から右(→)として扱う、という不具合を見せる場合があります(日本語版だから?)。あるいは、上位のランの方向ではなく、後方の文字の方向をとったりと、不具合に一貫性が無いのも特徴的です。何度かコピー&ペーストを繰り返すと「正しい表示順」になったりもします。

いずれにしても、Word(その他のアプリケーションも含め)の不具合テストをする時間はあまりとれません。私たちとしては「正しい論理順」のテキストデータを作成した上で、それに若干の細工を施すしかない。

4.1. 中立文字の奇妙な振る舞い

中立文字(空白類や括弧類)は、異なる強い方向性を持つ 2 つの文字に挟まれた場合は上方のランの方向をとります。ところが、なぜかそうならない場合はどうするのが良いでしょうか。

たとえば、次の例 4.1 では、段落全体を右から左(←)にしたところ、「(12)」という番号の後にスペースができ、番号とヘブライ文字の間にあったスペースが消えてしまいました(そのように見える結果になりました)。これは本記事冒頭(図 1b)で起きたことと同じです。奇妙な実現方向を赤字にしてあります。なお、正しい実現方向は例 3.1d を参照してください。

論理順 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20]
    ( 1 2 ) <SPC> מ ל ך <SPC> ( m ɛ l ɛ k h )
方向   * * * * * * * *
奇妙な実現方向 [ → [ → → ] → ] [ ← ← ] [ → → ]
表示順
[1]
(
[2]
1
[3]
2
[4]
)
[5]
<SPC>
[6]
מ
[7]
ל
[8]
ך
[9]
<SPC>
[10]
(
[11]
m
[12]
ɛ
[13]
l
[14]
ɛ
[15]
k
[16]
h
[17]
)
[18]
[19]
[20]
HTML による(論理順での)入力例
‭(12) מלך (mɛlɛḵ)「王」‬
あなたのブラウザではどう表示されているでしょうか
(奇妙に見えるよう調整してあります)
‭(12) ‬מלך‎ (mɛlɛkh)「王」
例 4.1

この場合は地道に、すべての括弧の前に <RLM>&#x200F;)を書き入れます。それでもうまくいかなければ、何度かコピー&ペーストを繰り返すか、新たな段落の中にコピー&ペーストすると意図通りの結果になる……場合があります。

HTML による(論理順での)入力例
‭&#x200F;(12‏) מלך &#x200F;(mɛlɛḵ‏)‏「王‏」‬
あなたのブラウザではどう表示されているでしょうか
‏(12‏) מלך ‏(mɛlɛḵ‏)‏「王‏」

4.2. 中立文字である括弧類の奇妙な振る舞い

前節と同じ種類の問題ですが、本来なら、開き括弧と閉じ括弧のペアが存在する時は、開き括弧の方向が閉じ括弧にも適用され、表示順において適切な括弧の向きになるよう反転処理がなされるはずです。ところが、Microsoft® Word 2016、あるいは Safari(15.5)は、何かの拍子に括弧の対応関係が崩れ、何かの拍子に正常化します。例 4.2 では奇妙な実現方向になる場合の一例を赤字にしています。

論理順 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20]
    ( 1 2 ) <SPC> מ ל ך <SPC> ( m ɛ l ɛ k h )
方向   * * * * * * * *
実現方向 [ → [ → → ] ] [ ← ← ] [ → → ] [ ← ]
表示順
[1]
(
[2]
1
[3]
2
[4]
)
[5]
<SPC>
[6]
מ
[7]
ל
[8]
ך
[9]
<SPC>
[10]
(
[11]
m
[12]
ɛ
[13]
l
[14]
ɛ
[15]
k
[16]
h
[17]
)
[18]
[19]
[20]
HTML による(論理順での)入力例
‭(12) מלך (mɛlɛḵ)「王」‬
あなたのブラウザではどう表示されているでしょうか
(12) מלך (mɛlɛkh)「王」
例 4.2

この場合も地道に、中立の方向性を持つ括弧の前後に <RLM> を書き入れて、方向を教えてやるしかない。ただ、なかなかアプリケーション側が「気づいてくれない」場合も多いので、根気良くコピー&ペースト、リロードを繰り返してください。

5. おわりに

本記事では Unicode 双方向アルゴリズムをざっくり概観しました。

以上の武器を使いながら、楽しく双方向テキストを作っていきましょう。

補足:HTML での双方向テキスト

HTML 4.01 / XHTML 1.0 には、<LRO><RLO> と同じことを行う bdo 要素が定義されており、HTML Living Standard でも残っています(2024 年 12 月 17 日版)。さらに、<LRI><RLI> と同じことをするための bdi 要素 が新たに定義されました。

Unicode 双方向アルゴリズムの技術報告の中に Unicode、HTML、CSS の対応表がありますから、可能であれば HTML、CSS で双方向テキストを作るのが楽と言えば楽です。本記事の HTML ソースでも bdi 要素を多用しています。