2020-12-12 ,

org-modeで文字をエスケープする方法

org-modeで文字が意図しない解釈をされてしまったことはないでしょうか。「_が下付きになっちゃった!」「テーブルの中に|を書いたらフィールドが分かれてしまった!」等々。

起きるたびに調べて場当たり的に対処してきたのですが、今日はorg-modeにおける文字のエスケープ、意図したとおりに解釈させる方法についてまとめてみました。(Org9.3.7時点)

Org entities

最も筋の良い方法はentityを使うことです。

entityというのはLaTeX風の記法で記号を文書中に挿入できる仕組みです。HTMLで言うところの実体参照のようなものです。

参考: Special Symbols (The Org Manual)

例えば_の場合、 \under{} と書くことで _ に置換されます。 {} の部分は無くても良いのですが、あった方が区切りが明確になって助かる場合があります。例えば a_b が下付きで表示されて困る場合は a\under{}b と書きます。org-modeではこのような書き方が出来る文字が多数定義されています。

M-x org-entities-help を実行するとその書き方の一覧が見られます。実際にやってみると多数の記号が表示されます。

これだとよく引っかかる文字が分かりづらいので、org-modeで実際に特殊な意味で使われている記号をピックアップし、それに対応するentityを表にしてみました。

記号 entity 使われているところ(マニュアルの該当箇所)
[   timestamp, link, image, foot note, priority, subtask fraction, checkbox
< lt timestamp, link target, column group, column width
> gt column group
| vert table
#   comment, block, meta, table row
\   latex, line break, entity
.   list
$ dollar latex, table row
: colon drawers, property, fixed-width area, tag, list
-   list, horizontal line, shy hyphen, dashes, dots
^ asciicirc superscript, table row
@   export snippets
{   macro
* star bold, headline, list, table row
/ slash italic, table row
_ under underline, subscript, table row
+ plus strike through, list, table.el
= equal verbatim, table formula
~ tilde code
!   table row
%   agenda
,   block

こうしてみると対応する書き方がない記号が目立ちます。特に \ (バックスラッシュ。円記号に見えていますか?)に対応する書き方がないのが致命的ですね。将来的に増えてくれれば良いのですが。

ユーザー定義のentityを加えることも出来るようですが文書の交換に支障が出るケースもあります。例えばGithubにREADME.orgとして上げる場合は org-entities-user に何かを加えたところで解決にはならないでしょう。

HTMLの数値文字参照のように任意のコードポイントを指定できるような機能があれば良いのですが。

何かで包む

~(code) や =(verbatim) で囲むと文字の解釈を抑制できる場合があります。

~\under{}~ と書くことで最初の\はそのまま表示されます。

codeやverbatimの意味的に使いたくないケースはあるでしょうし、中に入る文字次第では抑制できません。

他にもソースブロックやexampleブロックで文字の解釈を抑制できる場合があります。

#+begin_example
exampleの中に \under と書くと最初の\はそのまま表示されます。
#+end_example

しかし代わりに別の文字(行頭の# , *)が特殊な解釈をされることになります。

ちなみにこれらのブロックの中では、行頭に,を入れることで行頭の#や*をエスケープできます。

#+begin_src org
,#+begin_example
exampleの中に \under と書くと最初の\はそのまま表示されます。
,#+end_example
#+end_src

fixed-widthエリアは行指向なので比較的問題が起きにくい気がします。

: \underと書けるし
: :コロンも先頭に書ける

設定で回避する

一部の文字は設定で解釈を変更できます。

オプション指定 意味
#+OPTIONS: ^:nil a^b a_b を変換しない
#+OPTIONS: ^:{} a^{b} a_{b} の書き方のみ許容
#+OPTIONS: *:nil *word* _word_ /word/ +word+ を変換しない
#+OPTIONS: -:nil \- -- --- ... を変換しない
#+OPTIONS: tex:verbatim \begin $ 等のTeX表記を変換しない

参考: Export Settings (The Org Manual)

Export snippetsを使う

Export snippets は #+begin_export のインライン版です。 @@NAME:VALUE@@ という書き方で、NAMEで指定したバックエンドでエクスポートする内容をVALUEで指定できます。

参考:

文字をエスケープする良い方法はないかと探していたところ、Stack Exchangeにこの仕組みを使ったやり方が載っていました。

参考:

例えば次のように書くことで A[[B]]C になります(LaTeX, HTML両方でそうなるはずですがLaTeXは未確認)。

A@@latex:\char91\char91@@@@html:&#91;&#91;@@B@@latex:\char93\char93@@@@html:&#93;&#93;@@C

これだとさすがにつらいので、マクロを併用して次のようにします。

#+MACRO: BO @@latex:\char91@@@@html:&#91;@@
#+MACRO: BC @@latex:\char93@@@@html:&#93;@@

A{{{BO}}}{{{BO}}}B{{{BC}}}{{{BC}}}C

もちろんリンクの中でも使えます。

[​[https://google.com/search?q=%5d][Search result of {{{BC}}}]]

次のようなマクロを定義して直接コードポイントを指定することも可能です。

#+MACRO: char @@html:&#$1;@@
{{{char(169)}}}Misohena Laboratories

zero width spaceを挟む

見えない空白を入れることで無理矢理解釈を変更できます。

参考: Escape Character (The Org Manual)

見えない空白を挿入するには、 C-x 8 RET zero width space と入力します。

例えば[と[の間に見えない空白を入れることでリンクと解釈されることを防げます。

検索に支障を来すこともあり得ますし正直あまり良い方法とは思えませんが、強力な方法ではあると思います。

Export snippetsを使う(2)

状況にも依りますが、zero width spaceの代わりにexport snippetsで空の文字列を挿入するという手もあります。

[@@ascii:@@[https://example.com/]] ←ブラケットリンクにならない!

バックエンドにはasciiを指定していますが、これだけでどのバックエンドでも効果があります。何なら @@-:@@ でも大丈夫なようです。

最初はマクロで空文字列を挿入しようと思ったのですが、残念ながら効果が無くリンクと解釈されてしまいました。

#+MACRO: empty-str (eval "")
[{{{empty-str}}}[https://example.com/]] ←ブラケットリンクになる

マクロを使うなら、マクロでexport snippetsを生成するのが良いでしょう。

#+MACRO: empty @@ascii:@@
[{{{empty}}}[https://example.com/]] ←ブラケットリンクにならない!

[{{{empty}}}[https{{{empty}}}://example.com/]] ←リンクにならない!

最後に

軽量マークアップ言語では限られた記号を何に使用するかが設計上の最大のポイントになります。そして何かの意味に使用した記号を元の意味で使うための逃げ道をどう用意するかも工夫のしどころとなります。

org-modeの文法はこの辺りがうまく設計されていないなと前々から感じていました。今回調べてみてもまだ釈然としない部分が残っています。文脈によってエスケープする必要のある文字やエスケープする方法は変わってくるので、全てを網羅するにはもっとちゃんとした調べ方をしないとダメそうです。

Pingback / Trackback