Author Archives: AKIYAMA

2026-03-20 ,

org-modeでHTMLエクスポート時にMathMLを直接出力する(2026)

数式のエクスポートの話題をしたついでに、HTMLエクスポート時にLaTeX部分を直接MathMLで出力する方法について書いておこうと思います。

というのも10年以上前に同じネタで記事を書いたのですが、とっくの昔にその方法では動かなくなっていました。なので情報を更新しておこうと思いまして。ChromeもMathMLに対応しましたしね。正直対応する日が来るとは思っていませんでした。

org-latex-to-html-convert-commandの怪

それでLaTeX部分のエクスポート形式を変える方法を調べたのですが、今のorg-modeにはorg-latex-to-html-convert-commandというカスタマイズ変数があります。

;; org.elより
(defcustom org-latex-to-html-convert-command nil
  "Shell command to convert LaTeX fragments to HTML.
This command is very open-ended: the output of the command will
directly replace the LaTeX fragment in the resulting HTML.
Replace format-specifiers in the command as noted below and use
`shell-command' to convert LaTeX to HTML.
%i:     The LaTeX fragment to be converted (shell-escaped).
        It must not be used inside a quoted argument, the result of %i
        expansion inside a quoted argument is undefined.

For example, this could be used with LaTeXML as
\"latexmlc literal:%i --profile=math --preload=siunitx.sty 2>/dev/null\"."
  :group 'org-latex
  :package-version '(Org . "9.7")
  :type '(choice
          (const :tag "None" nil)
          (string :tag "Shell command")))

ここにLaTeX表記をHTMLへ変換するコマンドを書いて、後はorg-html-with-latex変数を 'html にすれば(もしくは #+OPTIONS: tex:html を指定すれば)良いらしいです。

……本当に?

(setq org-html-with-latex 'html)

実際やってみるとインラインで書いている部分は変換されるのですが、 \begin{...} ~ \end{...} で書いている部分(environment)は変換されませんでした(Org 9.8時点)。

ox-html.elの中を調べてみると、org-html-latex-fragment関数の中には確かに :with-latexhtml であるときの処理が書かれています。しかしorg-html-latex-environment関数の中には :with-latexhtml であるときの処理は一切書かれていません!

ナンデ!?

よく分かりませんがなぜかそうなっています。結局org-modeで標準的にサポートしているのはMathjaxを使用した方法だけだと考えるしかないでしょう。メーリングリストを漁れば何か経緯が分かるかもしれませんが面倒なので調べていません。

ちなみにorg-latex-to-mathml-convert-commandという変数もあるのですが、これはODTエクスポート時にしか効果がありません。以前書いた記事では、これをHTMLエクスポート時にも無理矢理使う方法を書きました。でも今更そんな方法でやりたくはありません。

さらに肝心の変換コマンドですが、docstringにはlatexmlcというコマンドを使う方法が書かれています。これはLaTeXMLというPerlで書かれたコンバーターに含まれているものですが、私の環境(MS-Windows)ではうまくインストールできませんでした。頑張れば出来るかもしれませんが、このためだけにStrawberry Perlを入れてCPANがちゃんと動くような環境を維持するのもバカらしいです。

他の方法を色々模索しましたが、最終的にはPandocを使う方法に落ち着いたので今回はそれを書こうと思います。Pandocは入手しやすいですし。

設定

init.elかなにかに次のように書きます。

;; 設定上は`mathjax'にすることによってlatex-environmentでも変換処理をさせる。
;; `org-html-latex-environment'はなぜか`html'を認識しない。
;; `org-html-latex-fragment'は認識する。
(setq org-html-with-latex 'mathjax)

;; mathjax用のHTMLヘッダー(JavaScript)は必要ない。
(setq org-html-mathjax-template "")

;; processing-typeが`mathjax'のときは`html'に書き替えることで
;; `org-format-latex-as-html'関数を無理矢理呼ばせる。
;; 経路:
;; org-html-latex-{environment|fragment}
;;   => `org-html-format-latex'
;;     => `org-format-latex'
;;       => `org-format-latex-as-html'
(defun my-org-format-latex:around (old-fun
                                   prefix &optional beg end dir overlays msg
                                   forbuffer processing-type)
  (funcall old-fun prefix beg end dir overlays msg forbuffer
           (if (eq processing-type 'mathjax)
               'html
             processing-type)))
(advice-add #'org-format-latex :around #'my-org-format-latex:around)
;; (advice-remove 'org-format-latex 'my-org-format-latex:around)

;; `org-format-latex-as-html'をpandoc用のものに置き換える。
(defun my-org-format-latex-as-html (latex-fragment)
  "Convert LATEX-FRAGMENT to HTML."
  (let* ((cmd "pandoc --mathml -f latex")
         (html
          ;; 引数で渡すと問題が起きがちなので標準入力で渡す。
          (with-temp-buffer
            (insert latex-fragment)
            (let ((coding-system-for-read 'utf-8)
                  (coding-system-for-write 'utf-8)) ;; 私の環境だと文字化け防止に必要
              (message "Running %s" cmd)
              (shell-command-on-region (point-min) (point-max) cmd nil t))
            (buffer-string))))
    ;; <p>と</p>\nを除去
    ;; (pandocの変換結果は<p>タグで囲まれている。
    ;;  texmathを使えば囲まないように出来るらしい。
    ;;  参考: https://news.ycombinator.com/item?id=43883052)
    (if (string-match "\\`<p>\\(.*\\)</p>[\n\r ]*\\'" html)
        (match-string 1 html)
      ;; マッチしない。pandocの仕様が変わった?
      html)))
(advice-add #'org-format-latex-as-html :override #'my-org-format-latex-as-html)
;; (advice-remove #'org-format-latex-as-html #'my-org-format-latex-as-html)

あとはPandocをインストールしてPATHを通しておいて下さい。

org2blogで使う場合(まさにこのブログ)は org2blog/wp-use-wp-latexnil にしないとダメだと思います。

結果

これは $x^2$ です(~$ .. $~ を使用)。

これは \( x^2 \) です(~\( .. \)~ を使用)。

これは $$ x^2 $$ です(~$$ .. $$~ を使用)。

これは \[x^2\] です(~\[ .. \]~ を使用)。

\begin{equation}
x^2 + y^2 = r^2
\end{equation}

\begin{gather}
 (a+b)^2 = a^2 + 2ab + b^2           \\
 (a-b)^2 = a^2 - 2ab + b^2           \\
 (a+b)^3 = a^3 + 3a^2b + 3ab^2 + b^3 
\end{gather}

以下は実際のエクスポート結果です。

これは x2x^2 です($ .. $ を使用)。

これは x2x^2 です(\( .. \) を使用)。

これは x2x^2 です($$ .. $$ を使用)。

これは x2x^2 です(\[ .. \] を使用)。

x2+y2=>r2\begin{equation} x^2 + y^2 => r^2 \end{equation}

(a+b)2=a2+2ab+b2(ab)2=a22ab+b2(a+b)3=a3+3a2b+3ab2+b3\begin{gather} (a+b)^2 = a^2 + 2ab + b^2 \\ (a-b)^2 = a^2 - 2ab + b^2 \\ (a+b)^3 = a^3 + 3a^2b + 3ab^2 + b^3 \end{gather}

設定の説明

一番の問題はorg-html-latex-environment関数が :with-latex'html のときを一切考慮していない点にあります。考慮していないので、フォールバック的な出力、つまりLaTeXのコードをdivやspanで囲んでそのまま出力するという処理になります。考慮しているケースは t または mathjax のとき(デフォルト)と、画像化するとき(org-preview-latex-process-alistのキーであるとき)だけです。

素直に解決しようと思ったらorg-html-latex-environmentにadviceを仕掛けて 'html であるときの処理を追加することになるでしょう。しかしそれだとorg-html-latex-environment関数の頭の部分で行っている共通処理をコピーしなければならなくなります。

なので :with-latex'mathjax で使うことにします。その上で、org-format-latex関数にadviceを仕掛け、 'mathjax だったときは 'html に書き替えてしまいます。すると 'mathjax が指定されているのにもかかわらず 'html が指定されていたときの処理であるorg-format-latex-as-htmlが呼び出されるので、後はコマンドラインでLaTeXからMathMLへ変換するだけです。

ただ、今回Pandocで変換するにあたって、org-latex-to-html-convert-commandでは若干指定しづらいところがありました。なのでorg-format-latex-as-html自体を丸丸置き換えて対処しています。頑張ればコマンドラインの指定だけでも何とかできると思いますが、私はシェルスクリプトよりもEmacs Lispの方が得意ですので。

そして最後にorg-html-mathjax-templateを空文字列にしてMathJax用のHTMLヘッダー(JavaScript)が出力されないようにしました。不要ですし、あるとせっかくのネイティブなMathMLがMathJax用の要素に置き換えられてしまいますので。

LaTeXからMathMLへの変換コマンド

今回LaTeXからMathMLへ変換するプログラムとしては次のものを検討しました。

mathtoweb 古い。Java依存
LaTeXML (MS-Windowsで)インストールできなかった
Pandoc 出力の一番外側のpタグとアノテーションを消したい
texmath Pandocが使っているライブラリ。Haskellでのビルドが必要
latex2mathml(python) 入力の一番外側を処理できない

他にも無数のプログラムがあるみたいです。

org-latex-to-html-convert-commandに直接指定できるものもありますが、シェルスクリプトでラップしないと厳しいものもあります。

おしまい

それにしてもなんでorg-html-latex-environmenttex:html に対応していないのか謎すぎますね。fragmentだけでいいからカスタマイズできるようにして! みたいな要望でもあったのでしょうか。……ひょっとして番号付けなどで個別に処理すると正しい結果にならない場合があるからとか? そういえば式番号出てませんね。そもそもちゃんとしたLaTeXの処理系に対してどこまで再現性があるものなのかは分かりません。

2026-03-18 ,

Emacs Calcの埋め込まれた数式からorg-modeの値を参照する

前回、org-mode文書の中にCalcの数式を埋め込む話をしました。しかし課題として埋め込んだ数式からorg-modeの各値(テーブル、リスト、他のソースコードブロックの結果、等々)を参照できないという問題が残りました。インラインソースコードブロックであれば src_calc[:var tbl=table1]{...} のように書けば参照できますが、Calcの埋め込みモードにはそのような仕組みはありません。ただ、Calc用の関数を作ってしまえば実現可能なはずです。なので今回はそれを実装してみました。

作成したコードと使い方

作成したコードは次の通りです。

(defun calcFunc-orgref (refspec)
  (save-current-buffer ;; 現在のバッファを保存・脱出時に復元
    ;; 式が埋め込まれているバッファを選択
    ;; (呼び出し時点では *Calculator* バッファが選択されているので)
    (calc-embedded-original-buffer t calc-embedded-info)

    (my-calc-value-from-elisp ;; Calc用の値へ変換
     (org-babel-ref-resolve ;; 参照を解決
      ;; Calcの式REFSPECを文字列へ変換する
      (my-calc-expr-to-string refspec)))))

(defun my-calc-expr-to-string (expr)
  "Calcの式を文字列へ変換します。"
  (pcase expr
    ;; ベクトル "table-1"
    (`(vec . ,elements)
     (apply #'string elements))
    ;; 変数 table1 or table#1
    (`(var ,dname ,vsym)
     (if (seq-contains-p (symbol-name dname) ?#)
         ;; 表示名に#が入っていたら変数名シンボルの方を使う
         (symbol-name vsym)
       (symbol-name dname)))
    ;; TODO: (calcFunc-subscr (var <name> var-<name>) ???)みたいなのも無理矢理 <name>_??? にする? (???の部分は数だったり変数だったりすると思う)
    (_ (error "Cannot convert to string from %s" expr))))

(defun my-calc-value-from-elisp (value)
  "Emacs Lispの値をCalcの値へ変換します。"
  (cond
   ;; 整数はそのまま
   ((integerp value) value)
   ;; 浮動小数点数は……良い方法が分からない。
   ;; とりあえず文字列化してから読み込んでみる。
   ((floatp value) (math-read-number (number-to-string value)))
   ;; 文字列は整数のベクトルへ
   ((stringp value) (cons 'vec (string-to-list value)))
   ;; リストはベクトルへ(要素は再帰的に変換)
   ((listp value)
    (cons 'vec (mapcar #'my-calc-value-from-elisp value)))
   ;; その他の型はとりあえずそのまま返してみる
   (t value)))

これを使うと次のように書けます。(前回定義したマクロも使っています)

# ■テーブルを参照する例

#+NAME: fruits
| Name   | Quantity |
|--------+----------|
| Apple  |       15 |
| Orange |       24 |
| Banana |        3 |
|--------+----------|
|        |       42 |
#+TBLFM: @>$2=vsum(@I..@II)

りんごは{{{calc(orgref(fruits)_3_2 => 15)}}}個、オレンジは{{{calc(orgref(fruits)_4_2 => 24)}}}個、バナナは{{{calc(orgref(fruits)_5_2 => 3)}}}、合計{{{calc(subvec(orgref(fruits), -1)_1_2 => 42)}}}個の果物があります。

# ■リストを参照する例

#+NAME: list-ex1
- 10
- 20
  - 22 (←無視される)
  - 24 (←無視される)
- 30

リストを参照すると $orgref(list#ex1) => [10, 20, 30]$ のようになります。(注意:マクロを使うと , がマクロの引数区切りになるので [10 までしかエクスポートされない!)

# ■コードブロック(と上のリスト)を参照する例

#+name: list-sum
#+begin_src elisp :var lst=list-ex1
(apply #'+ lst)
#+end_src

リストの値の合計: {{{calc(orgref(list#sum) => 60)}}}

制作過程

こんなの簡単に実装できるだろうと思ったら色々と難しいところがありました。

  • カレントバッファの調整
  • 文字列を扱うのが難しい!(表示をコントロールするのが難しい!)
  • どうやって参照先の値を取得するか
  • 得られた値をCalc向けの形式へ変換

Calc用の関数を定義

Calc用の関数を作ること自体は簡単です。関数名を calcFunc- で始めるだけです。

(defun calcFunc-orgref (refspec)
  ...
  )

これでCalcの数式の中から orgref(...) という形式で関数を呼び出せるようになります。

defmathというマクロを使う方法もありますが、どのような展開をするのか十分分かっている人でないと使うのが難しいですし、今回のような少し変わった用途の関数には向かないと思います。

問題は関数の中身。

簡単に思いつく仕様としては

  1. 参照の指定、つまり :var NAME=ASSIGN (参照: Environment of a Code Block)の ASSIGN 部分の文字列を引数に取り
  2. 参照先の値を取得し
  3. その値を返す

というだけのものです。

参照を解決

:var の処理をする関数はorg-babel-ref-resolveなので、単純に書けば次のようになるでしょう。

(defun calcFunc-orgref (refspec)
  (org-babel-ref-resolve refspec))

試してみましょう。

#+NAME: src1
#+begin_src elisp
123
#+end_src

$orgref("src1")=>$

$orgref("src1")=>$ の部分で C-x * u (update)すると……

$orgref([115, 114, 99, 49]) => orgref([115, 114, 99, 49])$

ナンデ!?

Calcにおける文字列の扱いと表示切り替え

何でかと言えば第一にCalcでは文字列は整数のベクトルだからです。第二にベクトルを文字列として表示するモードが有効になっていないからです。

文字列の表示モードを有効にするには、式の所で C-x * e を押してembedded modeに入り、 d " を押します(その後 q でembedded modeを抜けます)。すると次のようになります。

# [calc-mode: strings: t]
$orgref("src1") => orgref("src1")$

これで良さそうに見えますが、しかしこれでは通常の整数のベクトルも文字列として表示されてしまいます。つまり [1,2,3]"\^A\^B\^C" と表示されてしまうのです。

一つの式の中で都合良く一部だけを文字列表示にして他の部分をベクトル表示にするという方法は見当たりませんでした。

まぁ、ひとまず orgref([115, 114, 99, 49]) になってしまうのは我慢しましょう。必要なら今操作したように表示モードを切り替えれば済む話です。

CalcのベクトルからEmacs Lispの文字列への変換

次の問題は評価結果が => orgref([115, 114, 99, 49]) になっている点です。これは期待した結果とは違います。期待した結果は参照先のsrc1が評価された結果、つまり 123 です。

原因はここまでの話を見れば察しの良い人はすぐに気がつくでしょう。関数 orgref の引数 refspec に引き渡されるのはCalcのベクトル [115, 114, 99, 49] であって、Emacs Lispの文字列では無いからです。つまり、org-babel-ref-resolve関数に引き渡す前にEmacs Lispの文字列に変換する必要があるわけです。

CalcのベクトルはEmacs Lispから見れば (vec 要素1 要素2 要素3 ...) という形式のリストです。carがシンボルvecでcdrが要素リストであるようなコンスセル (vec . 要素リスト) だと言っても良いでしょう。

となると変換するには次のようにします。

(defun calcFunc-orgref (refspec)
  (org-babel-ref-resolve
   ;; (vec . 要素リスト)を要素リストの文字列へ変換
   (apply #'string (cdr refspec))))

というわけでもう一度試してみましょう。すると次のようなエラーが出ました。

org-babel-ref-resolve: Reference ‘src1’ not found in this buffer

カレントバッファの切り替え

src1がバッファ内に無いと言っています。あれー、おかしいなぁ……。 calcFunc-orgref の定義部分で C-u C-M-x を押してEdebug可能にして再度実行。ステップ実行して調査するとすぐに原因は分かりました。

カレントバッファが *Calculator* になっています! そりゃ見つからないわ。埋め込みモードは背後でCalcのバッファと繋がっていて、式を評価するときはそっちがカレントバッファになっているんですね。

現在実行中の埋め込みモードの情報はcalc-embedded-info変数に入っていて、埋め込み元のバッファもそこからたどれます。それを利用すると、次のようにして元のorg-modeのバッファに切り替えられます。

(defun calcFunc-orgref (refspec)
  (save-current-buffer ;; ←★現在のバッファを保存・脱出時に復元
    (calc-embedded-original-buffer t calc-embedded-info) ;; ←★式が埋め込まれているバッファを選択

    (org-babel-ref-resolve
     ;; (vec . 要素リスト)を要素リストの文字列へ変換
     (apply #'string (cdr refspec)))))

再度実行すると望みの結果が得られました。

$orgref([115, 114, 99, 49]) => 123$

結果となるEmacs Lispの値をCalcの形式へ変換

次はテーブルを参照してみましょう。

#+NAME: table1
| 1 | 2 |
| 3 | 4 |

$orgref("table1")=>$

$orgref("table1")=>$ の部分で C-x * u (update)。ん? 何かエラーが出ましたよ?

math-normalize-fancy: Can’t use multi-valued function in an expression

察しの良い人はもうお分かりだと思いますが、入力だけでなく出力も変換してやる必要があるのでした。さっきの例は結果が整数だったので良かったのですが、今回は結果はテーブルです。Emacs Lispレベルではorg-modeのテーブルはリストのリストになりますが、Calcレベルではベクトルのベクトルにしなければなりません。Calcのベクトルとは先ほども言及したように先頭がシンボルvecのリストです。

ひとまず変換する関数を書きましょう。

(defun my-calc-value-from-elisp (value)
  (cond
   ;; 整数はそのまま
   ((integerp value) value)
   ;; 浮動小数点数は……良い方法が分からない。
   ;; とりあえず文字列化してから読み込んでみる。
   ((floatp value) (math-read-number (number-to-string value)))
   ;; 文字列は整数のベクトルへ
   ((stringp value) (cons 'vec (string-to-list value)))
   ;; リストはベクトルへ(要素は再帰的に変換)
   ((listp value)
    (cons 'vec (mapcar #'my-calc-value-from-elisp value)))
   ;; その他の型はとりあえずそのまま返してみる
   (t value)))

これを使えば次のように書けます。

(defun calcFunc-orgref (refspec)
  (save-current-buffer ;; 現在のバッファを保存・脱出時に復元
    (calc-embedded-original-buffer t calc-embedded-info) ;; 式が埋め込まれているバッファを選択

    (my-calc-value-from-elisp ;; ←★Calc用の値へ変換
     (org-babel-ref-resolve
      ;; (vec . 要素リスト)を要素リストの文字列へ変換
      (apply #'string (cdr refspec))))))

そして再度評価すると……

#+NAME: table1
| 1 | 2 |
| 3 | 4 |

$
orgref([116, 97, 98, 108, 101, 49]) => [ [ 1, 2 ]
                                         [ 3, 4 ] ]
$

うまく行きました!

ちなみに部分的に取り出すなら次のようにするみたいです。

2行1列の値: $orgref([116, 97, 98, 108, 101, 49])_2_1 => 3$

2行目: $orgref([116, 97, 98, 108, 101, 49])_2 => [3, 4]$

2列目: $mcol(orgref([116, 97, 98, 108, 101, 49]), 2) => [2, 4]$

参照先の変数名での指定

それにしても参照先を指定する文字列がちゃんと表示されない(ベクトル表示になってしまう)のはやっぱり嫌ですね。何とかならないものでしょうか。解決方法の方向性はいくつかあると思うのですが、あまり強引なことはしたくありません。

orgref("table1") がダメなのであれば、シンプルに orgref(table1) と書かせるのはどうでしょうか。つまり変数名 table1 を指定させるわけです。本当に table1 という名前の変数がすでにあったらその値に置き換わってしまいますが、無ければ変数は変数のままで引数に渡されます。

例えば次のような関数を作ってargに何が渡されるか調べてみると良いです。

(defun calcFunc-testvar (arg)
  (message "arg=%s" arg)
  0)

Calcの中で testvar(table1) を評価すると(table1 という変数が既に無ければ) (var table1 var-table1) というリストが渡されてきます(各要素はシンボル)。ここで table1 はCalcの中で表示するときの変数名を表し、 var-table1 は実際に値を保持するEmacs Lispの変数名です。

ちなみにCalcの数式の中で table-1 とは書けません。これは table から1を引くという意味になってしまいます。この問題に対応するためなのかは知りませんが、Calcの数式の中では table#1 という書き方ができます。この変数はEmacs Lispレベルでは var-table#1 ではなく、 table-1 に対応づけられます。つまり (var table#1 table-1) になるわけです。

それらを踏まえて引数に渡されたCalcの値を文字列へ変換する関数を書いてみましょう。

(defun my-calc-expr-to-string (expr)
  (pcase expr
    ;; ベクトル "table-1"
    (`(vec . ,elements)
     (apply #'string elements))
    ;; 変数 table1 or table#1
    (`(var ,dname ,vsym)
     (if (seq-contains-p (symbol-name dname) ?#)
         ;; 表示名に#が入っていたら変数名シンボルの方を使う
         (symbol-name vsym)
       (symbol-name dname)))
    ;; TODO: (calcFunc-subscr (var <name> var-<name) ???)みたいなのも無理矢理 <name>_??? にする? (???の部分は数だったり変数だったりすると思う)
    (_ (error "Cannot convert to string from %s" expr))))

これを使うとorgref関数は次のように書けます。

(defun calcFunc-orgref (refspec)
  (save-current-buffer ;; 現在のバッファを保存・脱出時に復元
    (calc-embedded-original-buffer t calc-embedded-info) ;; 式が埋め込まれているバッファを選択

    (my-calc-value-from-elisp ;; Calc用の値へ変換
     (org-babel-ref-resolve
      ;; ★↓Calcの式REFSPECを文字列へ変換する
      (my-calc-expr-to-string refspec)))))

これでめでたくテーブル名等がベクトルになるのを恐れずに書けるようになったわけです。

# "src1"の代わりに変数名src1で指定できる(本当にsrc1という名前の変数があったらダメ)
$orgref(src1) => 123$

# "table1"の代わりに変数名table1で指定できる
$
orgref(table1) => [ [ 1, 2 ]
                    [ 3, 4 ] ]
$

# src-2-1はsrc#2#1で指定できる
#+NAME: src-2-1
#+begin_src elisp
210
#+end_src

$orgref(src#2#1) => 210$

というわけで最初に書いたコードになったのでした。

おしまい

問題も残っているでしょうが、とりあえず最低限使えるものにはなりました。

とは言えそれほど使う機会があるでしょうか。元々、使うか分からないけれど簡単に作れるのだから作っておくか、という気持ちで作り始めたのですが、思った以上に手間がかかってしまいました。

素のEmacs Lispとの相互運用性を高めるような関数がもっとあれば良かったんですけどね。いや、あるのかもしれませんけど全部見ていないので分かりません。

2026-03-15 ,

org-modeの中でEmacs Calcを使う(主にインラインで)

前回、ソースコードブロックの代わりにCalcのEmbedded Modeを使う方法を紹介したので、そのあたりについてもう少し書いてみようと思います。

Calcの埋め込みモード(Embedded Mode)の基礎

org-modeはLaTeXの表記がある程度そのまま使えますしCalcの埋め込みモードはLaTeXをサポートしているので何も設定しなくてもorg-modeからCalcの埋め込みモードはある程度使えます。

一番簡単なのは $ で囲むことでしょう。(もちろん他にも \(~\)$$~$$\[~\]\begin{equation}~\end{equation} 等の表記が使えます(参考: Embedded LaTeX)。空行も数式の区切りとして使えます)

例えば次のように書きます。

1~4を足すと $1+2+3+4$ になります。

$ の中で C-x * u (update)を押すと 1+2+3+4 が計算されて 10 に置き換わります。

1~4を足すと $10$ になります。

数式の部分は C-x * f (new formula)の後に 1+2+3+4 と入れても良いですし、その場合はその後RPN電卓のように 2 * で2倍にしたりといった操作ができます。 q でquit。式をバッファに入力してから C-x * e を押す方法もあります。ただこのあたりの専用モードに移る使い方はCalcの操作に慣れていないと難しいですね。幸い移らなくても C-x * u (update)は使えます。

これだけだったら埋め込みモードを使う必要性は少ないです。 C-x * q でQuick Calcを呼び出して計算して結果をyankすれば済む話です。

今度は次のように => を加えてから C-x * u (update)を押します。

$1+2+3+4=>$

すると今度は次のように計算結果が => の後に挿入されました。

$1 + 2 + 3 + 4 => 10$

変数を使うこともできます。次のように打ってから C-x * u (update)を押すと変数xに256が記録されます。

$x:=256$

そして同じバッファの別の場所で次のように入力して……

$x^2=>$

C-x * u (update)を押すと次のように変化します。

$x^2 => 65536$

この時、バッファ内の二つの数式 $ x:= 256$$x^2 => 65536$ はアクティブ(活性)なものとして、その位置が記録されています。

なので $x := 256$$x := 65536$ に変更して C-x * u (update)すると、 $x^2 => 65536$ の方も更新されて $x^2 => 4294967296$ に自動的に変化します!

バッファを閉じてしまうとこのアクティブ状態は失われてしまいますが、再度ファイルを開いて C-x * a (activate) を押すとバッファの中にある :==> が検索されてその周囲が有効な数式であればアクティブ化されます。

このように作られた数式部分をエクスポートするとどうなるでしょうか。 $ で囲まれた部分はorg-modeではLaTeX fragmentと呼ばれています(参考: LaTeX fragments)。なので数式のフォーマットで出力されることになります(例: x 2 = > 65536 )。他のLaTeX表記($$~$$\[~\]\(~\)\begin{equation}~\end{equation})でも同様です。唯一、空行で区切られた数式だけは通常の段落として出力されます。また、当然ですが数式がコメント(#)の後に書かれていれば出力されませんし、その他状況によっては特殊な出力になることもあるかもしれません。

数式のフォーマットで出力されるのは大仰だと感じることも多いでしょう。また、出力されるときは数式全体が出力されるので => より左を省いて結果だけを出力するようなこともできません。

そういった問題はorg-modeのマクロを使うとある程度解決できます。

設定

ここではマクロの定義の他により気軽に使えるように区切りのパターンもいくつか余分に追加しています。

  • {{{calc(x := 123)}}}{{{calc(2 x => 246)}}} のようなマクロを追加
  • 式の区切りパターンを追加
    • インラインコードブロック src_???{ ... }
    • マクロ {{{???( ... )}}}
    • ブロック #+begin ... #+end
    • 非ASCII文字(日本語が出てきたら数式ではないものとする)
;; マクロ {{{calc(式)}}} を定義する
;;   {{{calc(左辺=>結果)}}}       => 結果のみエクスポート
;;   {{{calc(変数:=右辺=>結果)}}} => 結果のみエクスポート
;;   {{{calc(変数:=右辺)}}}       => 右辺のみ (空にして => を必須にしても良いが)
;;   {{{calc(式)}}}               => 式のみ (評価結果にしても良いが)
(defun my-org-macro-calc (expr)
  (cond
   ((string-match "=> *" expr) ;; Include x := y + 3 => 20
    (substring expr (match-end 0)))
   ((string-match ":= *" expr)
    (substring expr (match-end 0)))
   (t expr)))

(setf (alist-get "calc" org-export-global-macros nil nil #'equal)
      "(eval (my-org-macro-calc $1))")

;; org-modeでのCalc式の区切りパターンを追加。
;; 新しいマクロ表記({{{calc()}}})の他に$や\[等の従来のものも一応残す。
(setf (alist-get 'org-mode calc-embedded-open-close-formula-alist)
      (list (concat
             "\\`\\|^\n\\|\\$\\$?\\|\\\\\\[\\|^\\\\begin[^{].*\n\\|^\\\\begin{.*[^x]}.*\n\\|\\\\("
             "\\|{{{[a-zA-Z][-a-zA-Z0-9_]*(" ;;マクロ
             "\\|\\<src_[^ \t\n[{]+\\(\\[[^]]*\\]\\)?{" ;;インラインソース
             "\\|^#\\+begin[_:][^\n]*\n" ;;ブロック
             "\\|[[:nonascii:]]:? ?" ;;ASCII以外(お好みで)
             )
            (concat
             "\\'\\|\n$\\|\\$\\$?\\|\\\\]\\|^\\\\end[^{].*\n\\|^\\\\end{.*[^x]}.*\n\\|\\\\)"
             "\\|)}}}" ;;マクロ
             "\\|}" ;;インラインソース
             "\\|^#\\+end[_:][^\n]*\n" ;;ブロック
             "\\| ?[[:nonascii:]]"
             )))
;; C-x * a (`calc-embedded-activate')で検索するパターンを追加
;; 設定しなくても := や => は検索するので必要なのかどうか分からないが一応
(setf (alist-get 'org-mode calc-embedded-announce-formula-alist)
      (concat
       "# Embed\n\\(# .*\n\\)*\\|"
       "{{{calc(.*?)}}}"))
;; d p (`calc-show-plain')を使ったときに出力されるコメントの構文
;; 一応他のメジャーモードの時と同じように設定しておく
(setf (alist-get 'org-mode calc-embedded-open-close-plain-alist)
      '("# %% " " %%\n"))
;; C-x * f (`calc-embedded-new-formula') で数式を作るときに挿入する区切り
;; 設定しない方がいい? 余計かも
(setf (alist-get 'org-mode calc-embedded-open-close-new-formula-alist)
      '("{{{calc(" ")}}}"))

独自のcalcマクロの使用例

上の設定の後、org-modeのバッファに例えば次のように書きます。

# 杯数: $ servings := 3 $

# [calc-mode: float-format: (fix 3)]
{{{calc(servings => 3)}}}杯分を作るには、水を{{{calc(water := 250 servings => 750 )}}}ml、レモン果汁を{{{calc(lemon := 125 servings => 375)}}}ml使います。合わせると{{{calc(water + lemon => 1125)}}}mlとなり、果汁{{{calc(100 lemon / (lemon + water) => 33.333)}}}%のレモン水になります。

その後 C-x * a (activate)を押すと :==> を含む全ての式が「アクティブ」になります。

C-x * n (next)や C-x * p (previous)を押すとポイントを次のアクティブな数式や前のアクティブな数式へ移動できます(アクティブになっていることを確認できます)。

この状態で $ servings := 3 $34 に変更して C-x * u (update)を押すと、他の全てのアクティブな数式も更新されます。

もちろんエクスポートすれば次のようにシンプルな文章になります。

4杯分を作るには、水を1000ml、レモン果汁を500ml使います。合わせると1500mlとなり、果汁33.333%のレモン水になります。

非ASCII文字を区切りにする

上の設定では非ASCII文字も区切りとして追加しているので、より気軽に文章の中で数式を書くことができます。例えば次のように:

2025年10月1日の為替レートはrate_before := 148.170円/ドルだった。10月10日はrate_after := 153.090円/ドル。実に100 (rate_after / rate_before - 1) => 3.320パーセント上がったことになる。

文の中に三つの数式があるのが分かるでしょうか。区切りとして非ASCII文字を追加したため、 が区切りになってその間をCalcは数式と認識してくれるわけです。

もちろんエクスポートすると余分な式も出力されてしまいますが、自分だけが見るのであれば困ることも無いと思います。いちいち {{{calc()}}} で囲むのが面倒であればこういった方法もあります。

ただ、数式の中に非ASCII文字を書きたい人はこの設定は使えません。

$ で区切ることを許容できるならそちらを使う方が良いかもしれません。ただ、 $ は数式のフォーマットでエクスポートされてしまうとかエクスポート対象を結果や代入値に限定できないといった問題があるので独自のマクロを作ったわけです。でも $ の一文字区切りは魅力的です。 $ のエクスポートを今回のマクロと同じようにしてしまうという手はあるかもしれません。

ソースコードブロックを使う

似たようなことはソースコードブロックを使ってもできます。特にインライン版のソースコードブロックが有用です。

次のように書くと先ほどと同じことができます(式の部分でC-c C-cを押すと結果部分が生成される)。

1~4を足すと src_calc[:eval no-export]{1+2+3+4} {{{results(=10=)}}} になります。

= が付くのが気に入らなければ次のようにヘッダー引数 :wrap を指定すれば良いみたいです。(t で良いのかはイマイチよく分かりません。 :results wrap でもいけるみたいです)

1~4を足すと src_calc[:eval no-export :wrap t]{1+2+3+4} {{{results(10)}}}になります。

ちなみに数式部分だけ出力したければ :exports code を指定します。これは今回のテーマである計算するというところから少々はみ出していますが。

1~4を足す式は src_calc[:exports code]{1+2+3+4} と書きます。

変数を使うには……どうしたらいいんでしょうね。

#+CONSTANTS: は参照できないみたいなんですよね。他のソースコードブロックの結果かテーブルかリストか……。とりあえずテーブルを参照してみましょうか。

#+NAME: drink-params
| servings |   3 |
| water    | 750 |
| lemon    | 375 |
#+TBLFM: @2$2=250*@1$2::@3$2=125*@1$2

src_calc[:eval no-export :wrap t :var params=drink-params]{params_1_2} {{{results(3)}}}杯分を作るには、水を src_calc[:eval no-export :wrap t :var params=drink-params]{params_2_2} {{{results(750)}}}ml、レモン果汁を src_calc[:eval no-export :wrap t :var params=drink-params]{params_3_2} {{{results(375)}}}ml使います。合わせると src_calc[:eval no-export :wrap t :var params=drink-params]{params_2_2+params_3_2} {{{results(1125)}}}mlとなり、果汁src_calc[:eval no-export :wrap t :var params=drink-params]{100 params_3_2/(params_2_2+params_3_2)} {{{results(33.333)}}}%のレモン水になります。

だめだ、やってられん!

(2026-03-16追記)header-argsプロパティを使えばもっと簡単になる事に気がつきました。

* プロパティを使う方法
:PROPERTIES:
:header-args:calc: :eval no-export :wrap t :var servings=3 :var water=250 :var lemon=125
:END:

src_calc{servings} {{{results(3)}}}杯分を作るには、水を src_calc{servings water} {{{results(750)}}}ml、レモン果汁を src_calc{servings lemon} {{{results(375)}}}ml使います。合わせると src_calc{servings*(water + lemon)} {{{results(1125)}}}mlとなり、果汁 src_calc{100 lemon/(water+lemon)} {{{results(33.3333333333)}}}%のレモン水になります。

課題

埋め込みモードはorg-modeが提供する変数、つまり、ソースコードブロックの :var で参照できるものにアクセスできないのは残念なところです。

とはいえ、Calcの関数を作ってしまえばアクセスできるのではないでしょうか。

そのあたりはまた今度。

(2026-03-16追記) => のペアがverbatimとして認識されてしまうことが多々あるようです。 {{{calc()}}} で囲っている分には(=> は出力されないので少なくともエクスポート時には)問題にはならないのですが、 $ で囲ったり、nonascii区切りを使うとおきがち。何とかしたいところ。

(2026-03-18追記) , を含む式がマクロ表記内に書けないという欠点がありますね。 , はマクロに対する引数の区切りになってしまうので。これはベクトルが書けないということなのでつらい。回避策としては、コメントの中で $ で囲った式を書き、そこでいったん変数に格納してからマクロ表記内ではその変数を表示するだけに留めるくらいでしょうか。

(2026-03-20追記) 続きを書きました: Emacs Calcの埋め込まれた数式からorg-modeの値を参照する