徹底攻略！ LuaLaTeXでLuaコードを「書く」ためのコツ

Lua(La)TeXエンジンの特徴の一つとして**​「Lua言語の処理系が組み込まれている」​**ということがあります。それも、ただ単にLuaのプログラムが動くだけではなく、それを使って(La)TeXの動作を制御することができます。

これは特に、**​「LaTeXの上でプログラミング処理を伴うマクロ**（自作命令）**を作りたい」​**というユーザにとって強力な武器となりえる機能です。従来は、LaTeX上のプログラミング機能（[ifthen]やpgfforなどのパッケージ）は非常に限られた能力しかもたず、少々複雑な処理を伴うマクロを作成しようとすると、独特な文法をもつ**難解なTeX言語**:scream:に頼るしかなかった[^external]からです。“普通の”スクリプト言語であるLuaが使えることで、「LaTeX上のプログラミング」の幅が大きく拡がることは間違いないでしょう。

[ifthen]: https://qiita.com/zr_tex8r/items/71ae46c9c4e8cb575073
[^external]: 外部のプログラム言語処理系と連携する方式（PythonTeXパッケージなど）もありますが、それも制約が多くて不便でした。なお、今ではexpl3を使うという方法も考えられますが、expl3という言語自体がTeX言語の“異質性”を引きずっているため、TeX言語の知識を持たない人がexpl3を習得するのは現状では困難だと思われます。

しかし、実際にLuaLaTeX上でのLuaプログラミングを活用しようとすると、多くの場合すぐにある困難にぶち当たります。それは**​「LaTeX文書中でLuaコードを正しく書く方法が自明ではない」​**ということです。

この記事では、LuaLaTeX文書（LaTeXコード）中に所望の**Luaコードを「書く」ためのコツ**について解説します。

## 前提知識

* フツーのLuaの知識。
* フツーのLaTeXの知識。
* この記事では「Luaコードを書く」というトピックに焦点を絞るため、Luaと(La)TeXの連携に関するその他の話題（LuaTeXの`tex`モジュールの使い方、等）の解説はしません。

また、記事全体の方針としては**TeX言語の知識は全く仮定しません**。ただし、部分的にTeX言語学習者向けの内容を挟むことがありますが、そういう部分には:sushi:を付けて明示することにします。

## LuaLaTeXでLuaコードが書けない！

### 復習：Luaコードを「書く」方法

本題に入る前にまず、LuaLaTeX文書の中でLuaコードを利用する方法について簡単に復習しておきましょう。

LuaLaTeX文書の中でLuaコードを実行するには`\directlua`という命令を利用します。そして、Luaコードの中で`tex.sprint`などの「(La)TeXのコードを書き出す関数」を実行することで、外側のLaTeXの世界[^latex-world]とのやり取りができます。

[^latex-world]: この記事は原則としてLaTeXユーザ向けであるため、以降の解説では「LaTeX」で通しますが、実際には`\directlua`の外が純粋なLaTeXであるかは全く無関係なので、「TeXの世界」という方が正確です。

例えば、次の例ではLuaの`math.sqrt`関数を利用して2の平方根の近似値を求めて文書中に出力しています。

```tex:test-1.tex
% LuaLaTeX文書, 文字コードはUTF-8 (以下同様)
\documentclass[a4paper]{article}
\begin{document}
The answer is \directlua{tex.sprint(math.sqrt(2))}.
\end{document}
```

![code-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/dea65c4b-b737-6b86-c22d-d7c40bc9d078.png)

これを見ると、確かにLaTeXとの連携の手順は少し煩雑ですが、「Luaコードを書く」ことについては何も難しいことはないように思えます。

### Luaコードを「書けない」理由

しかし話はそんなに簡単ではありません。なぜなら「`\directlua`の中の文字列も特別扱いされず、**普通にLaTeXの字句解析・構文解析の規則が適用される**」という厄介な規則があるからです。

一見すると、「LaTeXの規則」はLaTeXユーザには見慣れたもののはずなので大した問題ではないようにも思えます。「LaTeXの規則」の何が厄介なのかを知るため、例をみてみましょう。次のコードの中の`\directlua`は何を出力するでしょうか？

```text:test-2.tex
\documentclass[a4paper]{article}
\begin{document}
The answer is \directlua{
  local val = 42 % 5
  -- Prints the value.
  tex.sprint(val)
}.
\end{document}
```

恐らく`% 5`は「5で割った余り」のつもりで書かれたのでしょうが、ご存じの通り、`%`はLaTeXのコメント開始文字であるため、`% 5`の部分は無視されます。すると、`val`には（2ではなく）42が代入されるので「42」が出力されるのでしょうか。

実行すると判る通り、この`\directlua`は実際には**何も出力しません**。

![code-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/b7fc1b5d-8aab-cf11-af2e-4a17f9f4a701.png)

その理由を理解するには「LaTeXでは改行文字は単に空白として扱われる」という規則[^latex-rule]を思い出す必要があります。つまり`\directlua`の中身は実際には次のように解釈されています。

:::note info
以下では空白文字を明示したい場合に`␣`と表記します。
:::

[^latex-rule]: この他にも「行頭の空白文字は無視される」という規則も適用されます。

```text
␣local val = 42 -- Prints the value. tex.sprint(val)␣
```

結局、`tex.sprint…`の部分は「Luaの行コメントの中にある」ことになるので実行されるはずがないのでした。このように普段見慣れているはずの「LaTeXの規則」もLuaコードの中で適用されると予想外の効果を引き起こすのです。

### :sushi:ガチTeX言語者向けの説明

実は、`\directlua`の引数の解釈の仕様は“TeX言語的”には極めて単純ですので、マッチョTeXプログラマ:muscle:向けの説明としてはこの仕様を述べれば十分でしょう。（要するに **\\write の引数と同様**に扱われます。）

  * 引数のトークン列を**完全展開**する。
  * 結果のトークン列を（`\detokenize`の規則で[^partoken]）脱トークン化して文字列に変換する。
  * 結果の文字列が「実行されるLuaコード」である。

[^partoken]: :sushi:ただし、1つだけ例外があり、`\par`という制御綴のトークンについては、（その現在の意味が何かに関わらず）本来は“`\par␣”という文字列になるところが代わりに空文字列に変換されるようです。

例えば次のようなコードを実行したとしましょう。

```text
\def\foo{tex.write}\def\bar#1{#1#1}\def\space{ }
The result is \directlua{ \foo (
    \bar\space\bar [\relax\noexpand  \foo\bar]%%
        )}.
```

ここで`\directlua`の引数をトークン列としてみると以下のようになります。

> `␣` `\foo` `(` `␣` `\bar` `\space` `\bar` `[` `\relax` `\noexpand` `\foo` `\bar` `]` `)`

これを（普通のTeXの規則で）完全展開すると以下のトークン列が得られます。

> `␣` `t` `e` `x` `.` `w` `r` `i` `t` `e` `(` `␣` `␣` `␣` `[` `[` `\relax` `\foo` `]` `]` `)`

従って、これを脱トークン化して得られる以下の文字列がLuaのコードとして実行されます[^long-string]。

[^long-string]: `[[…]]`はLuaのraw文字列リテラルです。`tex.write`を使っているため、結局、`…`の部分がそのまま出力されることになります。

```text
␣tex.write(␣␣␣[[\relax␣\foo␣]])
```

結局、以下のような出力が得られます。

![code-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/b9a64fbb-0da5-bb01-1dfa-f75886f3a575.png)

## LuaLaTeXでLuaコードを書く！

何やら恐ろしいTeX言語:scream:の話が出てきてしまいましたが、この話は同時に「`\directlua`を**LaTeXユーザが使いこなすのは絶望的に難しい**:sob:」という事実を示唆しています。つまり、`\directlua`の中の記述がどう解釈されるかを知るためには**難解なTeX言語の規則**を習得する必要があるわけです。TeX言語を避けるためにLuaを使いたいのに、結局そのためにTeX言語の知識が必要になるのでは本末転倒です。

### LaTeXユーザの希望、luacodeパッケージ

しかし実は、LaTeXの世界はこの問題に対しても**​「luacodeパッケージ」​**という解決法を与えています。この[luacodeパッケージ]は「LuaLaTeX文書中にLuaコードを書く」際に役立つ機能を提供するものです。以降ではこのluacodeパッケージの基本的な使い方を説明します。

[luacodeパッケージ]: https://www.ctan.org/pkg/luacode

luacodeパッケージの読込は、いつも通り`\usepackage`で行います。

```tex
% プリアンブルで
\usepackage{luacode}
```

### luacode*環境を使う

luacodeパッケージが提供する`luacode*`環境[^nonstar]は**​「Luaコードを“そのまま”書けるようにした \\directlua」​**に相当するものです。

[^nonstar]: `luacode*`という“\*-形”の環境があるなら`luacode`もあるはずで、事実、`luacode`は`\` `{` `}`の特殊扱いを保持して（所謂“準verbatim”の状態で）コードを記述する環境です。ただし私自身は、`luacode`は「Luaコードで必要な`\`を簡単に書けない」という問題があるため推奨せず、`luacode*`と生の`\directlua`だけ使い分ければ十分だと考えています

```tex
\begin{luacode*}
  ‹Luaコード記述›
\end{luacode*}
```

`luacode*`環境の中に書かれた文字列は、verbatim環境と同様に、LaTeXの特殊文字や空白や改行も含めてすべてそのまま読み取られ、結果の文字列がLuaコードとして（最終的には内部で`\directlua`を利用して）実行されます。

:::note info
`\end{luacode*}`の部分は他の文字を含まない単独の行として書かれる必要があります。また、この行の末尾の改行は空白にならずに無視されるようです。
:::

例えば、前出のtest-2.texの中に登場した「`%`や`--`を含むLuaコード」も`luacode*`を使うと意図通りに実行されます。すなわち、`%`は剰余の演算子と解釈され`--`は行末までをコメントアウトするので、結果的に「2」がLaTeX側に出力されることになります。

```text:test-2a.tex
\documentclass[a4paper]{article}
\usepackage{luacode}
\begin{document}
The answer is
\begin{luacode*}
  local val = 42 % 5
  -- Prints the value.
  tex.sprint(val)
\end{luacode*}
.
\end{document}
```

![code-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/a01ee9c6-722a-6682-57c4-2167fd846808.png)

### luacode*環境が使えない

`luacode*`を利用すると、「`\directlua`でLuaコードを書くのが困難」という問題の大部分が解決されますが、残念ながら`luacode*`は万能ではありません。以下で紹介するケースでは`luacode*`が使えません。

#### luacode*中でマクロ等を定義することはできない

`tex.sprint`では任意のLaTeXコードを出力できるので「`\newcommand`文を出力してマクロを定義する」なんてこともできそうです。実際、それは可能なのですが、`luacode*`を使うとうまくいきません。例えば、次のコードでは`math.sqrt(2)`の値（の10進表記）を`\myAnswer`というマクロに定義していますが、実際に`\myAnswer`を文書中で使おうとすると「未定義である」というエラーが発生してしまいます。

```text:test-3.tex(失敗)
\documentclass[a4paper]{article}
\usepackage{luacode}
\begin{luacode*}
  local v = math.sqrt(2)
  -- \newcommand 命令を出力してマクロを定義する…はず
  tex.sprint("\\newcommand{\\myAnswer}{"..v.."}")
\end{luacode*}
\begin{document}
% でもここでは \myAnswer は未定義!
The answer is {\myAnswer}. %==>! Undefined control sequence.
\end{document}
```

この失敗の原因は、「`luacode*`中で`tex.sprint`で出力したLaTeXコードは**luacode*環境の中で実行される**」からです。ご存じの通り、LaTeXの環境の中で何か設定（フォントなど）を変更した場合、その設定の効果は環境の中に限られます[^global-def]。この仕様はマクロ定義にも当てはまり、環境の中でマクロを定義してもその定義は環境の外に出ると消えてしまいます。

[^global-def]: つまり、環境の中は（素の）グルーピングの中と同じで**局所化**されているわけです。ただし、LaTeXの“設定変更”動作のうち「カウンタ値の変更」などのごく一部のものは局所化の影響を受けない仕様（つまり変更が**大域的**）になっています。:sushi:もちろん、TeX言語の`\gdef`等のプリミティブを使えば大域的にマクロを定義することが可能です。

```tex
\begin{center}
  \newcommand*{\myGreet}{Hello}% マクロ定義
  \huge \myGreet!
\end{center}
% ここでは \huge の効果も \myGreet の定義も消える
```

これと同じ原理で、先ほどの`luacode*`の例では、`\myAnswer`は「`luacode*`環境内で定義されている」ため`luacode*`環境の実行が終わった時点では未定義に戻ってしまうのです。

#### マクロの定義本体ではluacode*は使えない

LaTeXの悪名高い仕様として「`\verb`命令や`verbatim`環境は他の命令の引数の中では使えない」というものがあります（**​“\\verb の呪い”​**[^curse]）。実はこの仕様は「字句解析の仕様を変えるような機能」一般について成り立ち、件の`luacode*`もそれに該当します。つまり、「**luacode\* は他の命令の引数の中では使えない**」のです。

[^curse]: 私はこの仕様のことを「`\verb`の呪い」と呼んでいます。この制限はTeX言語の字句解析の仕様に起因するものであり、当該の機能の（TeX言語での）実装の工夫により解消することができないため、「制限が決して外れない」のいう意味合いを込めています。

この制限は、Luaを利用して複雑な挙動をもつマクロを作りたいというLaTeXユーザにとっては致命的です。それを実現しようとすると、「`\newcommand`の引数として記述するマクロの定義本体部分に`luacode*`を含める」必要が生じますが、“`\verb`の呪い”はそれを不可能にしています。

例えば、「LaTeX文書中に現在時刻の文字列を出力するマクロ」をLuaの`os.date`を利用して実装しようとします。`luacode*`を使うと以下のようなコードを書くことになるでしょう。

```text:test-4.tex(失敗)
\documentclass[a4paper]{article}
\usepackage{luacode}
\newcommand*{\myCurrentTime}{%
% ここは「\newcommandの引数の中」だからダメ!
\begin{luacode*}
  tex.sprint(os.date("%H:%M:%S"))
\end{luacode*}
}
\begin{document}
It is {\myCurrentTime} now.
\end{document}
```

しかし、マクロの定義本体を記述する`{…}`は「`\newcommand`命令の引数」に他なりません。従って、ここでは`luacode*`を使うことができないのです。

### LaTeXユーザがこの先生きのこる方法

結局、`luacode*`だけで全てを済ませることはできないことが判りました。しかも、その理由の一つは「`luacode*`がLaTeXの特殊文字の効果を消す」親切な機能をもつがゆえに「`\verb`の呪い」にかかってしまうからでした。となると、「TeX言語:scream:の複雑な規則」を完全に回避することは不可能なのでしょうか？

ここではこの困難な状況を**​「luacode\* と \\directlua の使い分けの戦略を工夫する」​**ことで乗り切ることにしましょう。以下のような方針をとります。

  * 可能な限り、`luacode*`環境を利用する。
  * `luacode*`環境が使えない場合に限って、可能な限りコードの量を絞った上で`\directlua`命令を利用する。
  * TeX言語:scream:を全く知らないLaTeXユーザでも解釈を予測できるように、**\\directlua の引数に書ける文字を制限する**。

大事なのは最後の「書ける文字を制限する」ということです。例えば、コードが完全に**LaTeXの特殊文字以外**からなるのであれば、`\directlua`を使っていてもそのまま読み取られるのは明らか[^whitespace]です。

[^whitespace]: 空白類文字はそのまま読み取られるわけではないですが、Luaの字句解析自体がフリースペースなので、空白類文字の解釈は文字列リテラル以外では問題にならないでしょう。

```tex
% Luaコードは"そのまま"読み取られる
\directlua{tex.print(math.sqrt(2))}
```

実際には非特殊文字だけでは不便なので、少し条件を緩和して以下の文字を使用可能と決めます。

  * LaTeXの特殊文字**以外**の全てのUnicode文字。
  * 特殊文字のうち、`$` `&` `_`の3つ。\
    ※これらは`\directlua`の中では特殊な挙動にならずにそのまま読み取られます。
  * 対になっている`{`と`}`の組。\
    ※命令の引数の位置にない限りは`{` `}`はそのまま読み取られますが、`\directlua`の引数の`{…}`の判定のため対になる必要があります。

逆に言うと、以下に挙げる文字は**一切使用禁止**とします。

  * 以下の文字： `\` `#` `^` `~` `%`
  * 対にならない`{`と`}`。

もちろん、このような「文字禁止縛り」を設けた上でのLuaプログラミングは不便であることは確かです。そこで「可能な限り`luacode*`を利用する」という方針と組み合わせるわけです。もう少し具体的に、以下のようにします。

  * 具体的な処理は**全て関数として切り出して luacode\* の中に書く**ことにして、`\directlua`の中の処理はなるべく[^possible]「別の場所で定義した関数を呼び出すだけ」にする。

[^possible]: 「なるべく」とあるように、こちらは厳密に規定された規則とはしていません。「使用禁止文字の規則」が気にならない程度であれば、「`\directlua`の中の記述」の範囲を拡げてもよいでしょう。

このように用途を限定する限りは`\directlua`の「使用禁止文字の規則」はほとんど問題にならないことが、少し試してみればわかります。（「マクロで文字列の引数を扱いたい」場合には問題が生じますが、それは後で扱います。）

### LuaLaTeXで実際にLuaコードを書いてみる

「戦略」の適用の例として、先ほどの「`luacode*`が使えないケース」のコードを「戦略」に従って書き直してみましょう。

まずは、test-3.texですが、これは要するに「最終的に`\directlua`で実行する必要がある」というわけなので、とにかく「何か関数を`\directlua`で呼び出す」というコードをまず書いてみます。

```tex
\directlua{ my_init() }
```

そうすると、Luaで書くべき残りの処理は「`my_init`の実装」だけです。こちらは`\directlua`で書く必要が全くないので、方針に従い`luacode*`の中に書くことになります。

```text
\begin{luacode*}
  function my_init()
    local v = math.sqrt(2)
    tex.sprint("\\newcommand{\\myAnswer}{"..v.."}")
  end
\end{luacode*}
```

全体のコードは以下のようになりました。

```text:test-3a.tex(成功)
\documentclass[a4paper]{article}
\usepackage{luacode}
% 実行する内容を関数にまとめてluacode*で定義する
\begin{luacode*}
  function my_init()
    local v = math.sqrt(2)
    tex.sprint("\\newcommand{\\myAnswer}{"..v.."}")
  end
\end{luacode*}
% その関数を \directlua で実行する
\directlua{ my_init() }
\begin{document}
% 今度は \myAnswer が正しく定義されている
The answer is {\myAnswer}.
\end{document}
```

![code-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/dea65c4b-b737-6b86-c22d-d7c40bc9d078.png)

test-4.texの方も方針はほぼ同様です。マクロ`\myCurrentTime`の定義本体の中では`\directlua`を使う必要があるため、ここを「関数を呼ぶだけ」のコードにします。

```tex
\newcommand*{\myCurrentTime}{%
  \directlua{ my_current_time() }%
}
```

あとは、Lua関数`my_current_time`の定義を`luacode*`の中に書くだけです。以下のようになりました。

```text:test-4a.tex(成功)
\documentclass[a4paper]{article}
\usepackage{luacode}
\begin{luacode*}
  function my_current_time()
    tex.sprint(os.date("%H:%M:%S"))
  end
\end{luacode*}
\newcommand*{\myCurrentTime}{%
  \directlua{ my_current_time() }%
}
\begin{document}
It is {\myCurrentTime} now.
\end{document}
```

![code-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/75f4cfc0-87ba-7048-a9eb-edeefc4e7141.png)

:::note info
もちろん、実際にはコンパイル時の時刻が出力されます。
:::

## LuaでLaTeXマクロしよう！

「Luaコードを書く」ためのコツがつかめたと思いますので、次は**​「Luaを利用して複雑な挙動をもつマクロを作る」場合の書き方のコツ**について解説を進めます。

:::note info
「LaTeXのマクロの定義の仕方」を復習したい人は、以下の記事を参考にしてください。

  * [完全攻略！ LaTeX のマクロ定義][latex-macro]
:::

[latex-macro]: https://qiita.com/zr_tex8r/items/5067307890d36c0e4882

### 「LuaでLaTeXマクロ」のキホン

先の節で扱ったtest-4a.texの例は、「Luaを利用して複雑な挙動をもつマクロを作る」場合の典型的なパターンを示しています。

 1. 現在時刻を出力するマクロ`\myCurrentDate`を作りたい。
 2. Luaの関数`my_current_date`を`\directlua`で呼ぶだけのマクロを`\myCurrentDate`として定義する。
 3. Luaの関数`my_current_date`を“フツーのLuaプログラミング”を駆使して実装し、そのコードを`luacode*`環境内に書く。

特に、2の部分はLaTeX（というよりTeX言語:scream:）とLuaが交錯する複雑怪奇な世界:skull:なので、LaTeXユーザはここの部分は定型コードで済ませて3の**関数の実装に注力する**べきです。3の関数の実装では「TeX言語:scream:の規則」を一切気にせずに済みます。

もう少し例を挙げてみましょう。次のようなマクロを作りたいとします。

  * `\myDice`：1～6の範囲の数字をランダムに選んで出力する。

まずはマクロの方を定義します。これは**何も考えずに**次のように書きます。

```tex
\newcommand*{\myDice}{%
  \directlua{ my_dice() }%
}
```

あとは、Lua関数`my_dice`の実装を**じっくりと考えましょう**。といっても、この場合は実装はほぼ自明ですが[^my-dice]。

[^my-dice]: 結果的に`my_dice`のコードの中には禁止文字は全く現れないので`luacode*`環境を使う必要はなかったことになりますが、だからといって「無駄に複雑なコードを書いた」ことにはなりません。大事なのは、「使用禁止文字の規則」禁止文字を**気にせずに**Luaコードを書けることですから。

```lua
  function my_dice()
    tex.sprint(math.random(6))
  end
```

これを`luacode*`の中に書けば完成です。

```text:test-5.tex
\documentclass[a4paper]{article}
\usepackage{luacode}
\begin{luacode*}
  function my_dice()
    tex.sprint(math.random(6))
  end
\end{luacode*}
\newcommand*{\myDice}{%
  \directlua{ my_dice() }%
}
\begin{document}
\myDice, \myDice, \myDice.
\end{document}
```

![code-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/e255b9af-8de9-19df-a332-125d9f6126a7.png)

:::note info
出力は実行のたびにランダムに変わります。（以下、`math.random`利用の例は全て同様。）
:::

### 補足：マクロできるとき・マクロできないとき

LaTeXの動作としては、「`\directlua`の実行」は「引数のないLaTeXマクロの実行」と同様の振る舞いをします。例えば、

```tex
\directlua{ tex.sprint(1 + 5 * 8 + 1) }
```

のような`\directlua`の実行は、

```tex
\newcommand*{\answer}{42}
```

のようなマクロが**予め定義されている**という前提で`\answer`を実行したのとほぼ同等の動作になります。

:::note info
:sushi:TeX言語者向け補足：`\directlua`は展開可能であり、単純化すると「`\directlua{‹Luaコード›}`を一回展開するとLuaコードが実行された上で『LuaコードがTeX側に書き出した内容』になる」と見なすことができます[^input]。従って、特に出力が展開不能トークン列である場合は、Luaで実装したLaTeXマクロは自動的に完全展開可能の性質を得ることになります。例えば、前出の`\myCurrentTime`を使って`\edef\myTime{\myCurrentTime}`を実行することで`\myTime`に**実行時の**現在時刻の文字列を代入できます。
:::

[^input]: :sushi:厳密にいうと、`\directlua`の展開の仕様は単純なトークン列置換ではなくて、`\input`によるファイル読込と同等です。例えば`\directlua{tex.sprint(1+5*8+1)}`の展開の場合、“`42`”とだけ書かれたファイルを`\input`するのと同等です。これはまた`\scantokens{42}`を展開したのとも同等といえます。（ただしこれらも完全に同等ではありません。）

このため、あるLaTeXの命令の引数について「中にマクロを含めてもよくてその場合はマクロの定義内容を書いたのと同等になる」という性質を満たす**のであれば**、その引数において`\directlua`（およびそれを定義内容とするマクロ）を含めることもできます。

例えば、一般に「数値（整数・実数）や長さ値の引数」はマクロを含めることが可能とされているので、先の節で紹介したマクロ`\myDice`について、次のようなコードを実行できます[^section]。

[^section]: `\section`を実行すると新しい節を始めたことになりsectionカウンタが増分されます。

```tex
% \setcounter の"代入する整数値"の引数をマクロにした
\setcounter{section}{\myDice}
\section{Random section number}% 節番号は2～7の範囲でランダムに選ばれる
```

![code-12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/2da15f3d-7aaf-852e-7104-a8a07ae48d2d.png)

ただし、現実問題としては引数が「マクロを含められる」という性質をもつかは仕様として明示されていない[^impl-depend]ことがほとんどです。このため、数値・長さ値以外の引数については、**マクロを含めるのは避けた方が無難でしょう**。

[^impl-depend]: :sushi:TeX言語の知識をもつ人であれば、対象の命令の実装を調べて動作を推定することができますが、仕様ではない以上、それは結局「実装に依存している」ことになってしまいます。

例えば、「マフラーの色を赤・青・緑の3色からランダムに選んだ**ゆきだるま**:snowman:」を出力する命令`\mySnowman`を作りたいとします（素敵:blush:）。このとき、色名を出す部分を`\myColor`として切り出した次のようなコードは“正しい”でしょうか？

```text
\usepackage{xcolor,scsnowman}% ゆきだるま☃!
\usepackage{luacode}
\begin{luacode*}
  local colors = {"red", "blue", "green!50!black"}
  function my_color()
    local ci = math.random(#colors)
    tex.sprint(colors[ci])
  end
\end{luacode*}
% \myColor は"red"などの色名を返す
\newcommand*{\myColor}{\directlua{ my_color() }}
\newcommand*{\mySnowman}{%
  \scsnowman[scale=1.5,snow,arms,hat,muffler=\myColor]%
}
```

実際に実行してみるとこのコードは期待通りの動作をします。しかし、`\scsnowman`命令の`muffler`の引数に「マクロを含められる」ことは保証されていないことを考えると、このコードは“正しい”とはいえないでしょう。実際、「:snowman:の帽子の色もマフラーに合わせたい」ということで、次のようにコードを書き換えると、ほとんど同じコードであるにも関わらず、こちらはエラーになっていまいます[^keyvalue]。

[^keyvalue]: 実際の挙動としては、値区切るのコンマ（`,`）やkey-valueの区切りの等号（`=`）の部分をマクロに含めると、多くの場合に想定外の動作を引き起こします。

```text
\usepackage{xcolor,scsnowman}% ゆきだるま☃!
\usepackage{luacode}
\begin{luacode*}
  local colors = {"red", "blue", "green!50!black"}
  function my_color()
    local ci = math.random(#colors)
    tex.sprint("hat="..colors[ci]..",muffler="..colors[ci])
  end
\end{luacode*}
% \myColor は"hat=‹色名›,muffler=‹色名›"を返す
\newcommand*{\myColor}{\directlua{ my_color() }}
\newcommand*{\mySnowman}{% これはダメ!
  \scsnowman[scale=1.5,snow,arms,\myColor]%
}
```

結局のところ、「引数（またはその一部）をマクロで置き換える」のは避けて、**​「命令全体をマクロで置き換える」という方針に徹する**のが安全です。今の場合は、`\scsnowman`命令全体をLuaで出力するようにすればよいわけです。

```text:test-6.tex
\documentclass[a4paper]{article}
\usepackage{xcolor,scsnowman,luacode}
\begin{luacode*}
  local sc = "\\scsnowman[scale=1.5,snow,arms,hat=%s,muffler=%s]"
  local colors = {"red", "blue", "green!50!black"}
  function my_snowman()
    local c = colors[math.random(#colors)]
    tex.sprint(sc:format(c, c))
  end
\end{luacode*}
\newcommand*{\mySnowman}{\directlua{ my_snowman() }}
\begin{document}
\mySnowman\mySnowman\mySnowman?
\mySnowman\mySnowman\mySnowman\mySnowman\mySnowman!!
\end{document}
```

![code-13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/5bae5b46-d73a-800f-f46e-f94ab6d7406e.png)

## 今度は引数付きでLaTeXマクロしよう！

これまで「LaTeXのマクロをLuaで実装する」話を続けてきましたが、そこでは専ら「引数をとらないマクロ」を扱いました。ここでは**​「引数をとるマクロ」を実装する方法**を解説します。

引数を扱おうとすると、`\directlua`の中でマクロの引数をLua側に渡す処理が必要になります。例によってこの処理は単純ではなく、正しく動作するコードを書くにはコツが要ります。ただし引数が数値（整数・実数）である場合は話はとても簡単なので、まずはそこから始めましょう。

### 数値の引数をどうにかする

`myDice`は1～6の範囲の乱数を発生させるものでしたが、ここで上限は6で固定はなく引数で指定できた方が便利でしょう。そこで次のような仕様のマクロを実装してみます。

  * `\myRandom{‹上限n›}`： 1～nの範囲の整数をランダムに選んでその10進表記を出力する。

`\myRandom`は引数を1つとるので、その定義は以下のような形になります。

```tex
\newcommand*{\myRandom}[1]{% #1=‹上限n›
  \directlua{ ... }% 中身は後で考える
}
```

`\directlua`の中身は後で考えることにしますが、とにかく「マクロの定義は`\directlua`の実行だけにする」という**原則は守る**ことにします。

Lua関数`my_random`の実装を先に考えましょう。とにかく上限nの値を使うのは確実なので、これを関数の引数にします。

```lua
  function my_random(n)
    tex.sprint(math.random(n))
  end
```

`my_random`の仕様をこのように決めたとすると、結局、次のような関係が成立している必要があります。

  * `\myRandom{42}`が実行されると\
    ↓\
    `\directlua{ my_random(42) }`が実行される。

すると、マクロ`\myRadnom`の定義は次のようにすればよさそうです。

```tex
\newcommand*{\myRandom}[1]{% #1=‹上限n›
  \directlua{ my_random(#1) }%
}
```

もちろん、`\directlua`中に`#`を書くのは**​「使用禁止文字の規則」に違反します**。しかし、そもそも「使用禁止文字の規則」の目的は「どう解釈されるかが（LaTeXユーザにとって）不明なものを`\directlua`中に紛れ込ませない」ことでした。一方で「マクロの引数の規則」はLaTeXユーザにとって周知のものなので、目的に照らせば問題は起こらないはずです。そこで、**​「使用禁止文字の規則」を改訂してしまう**ことにしましょう:upside_down:

  * マクロの定義本体中の`#1`、`#2`、…はマクロ実行時に与えられた実引数の内容に置き換わる。（LaTeXの規則）
  * 従って、当該の**マクロの仕様[^macro-spec]を前提**とするときに、`#1`、`#2`、…を実引数の内容に置き換えた結果が「使用禁止文字の規則」に決して違反しない**のであれば**、`#1`、`#2`、…を`\diretlua`の中に含めてもよい。

[^macro-spec]: もし（今実装しようとしている）マクロの引数に何でも入れてよいのであれば、そこに`~`や`\\`を含めることもできて、すると結局`\directlua`中に禁止文字が含まれてしまうことになります。従ってマクロの仕様として「正しい用法である限りそんなことは起こらない」という保証は必要です。

というわけで、先の`\myRadnom`の定義が晴れて採用できることになったので、マクロの実装が完成しました。

```text:test-7.tex
\documentclass[a4paper]{article}
\usepackage{luacode}
\begin{luacode*}
  function my_random(n)
    tex.sprint(math.random(n))
  end
\end{luacode*}
\newcommand*{\myRandom}[1]{% #1=‹上限n›
  \directlua{ my_random(#1) }%
}
\begin{document}
% 1～99999の整数がランダムに選ばれる.
Today's lucky number is \myRandom{99999}.
\end{document}
```

![code-14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/7287fd9e-5efd-5b57-6991-1089a5bdb0b3.png)

もう一つの例として、次のマクロを実装しましょう。

  * `\mySqrt{実数x}`： xの平方根の値を固定小数点表記[^fixed]で出力する。

[^fixed]: `1.23e-5`のような指数表現を使わずに`0.0000123`のように表すのが「固定小数点表記」です。(La)TeXの文法では実数値は全て固定小数点表記で表すため、マクロの出力を(La)TeXの数値として利用したい場合は固定小数点表記を指定する必要があります。ちなみに、TeXでは実数値の内部表現も固定小数点（小数部16ビット）であるため、常に小数部7桁の精度を指定すれば十分です。

今度は引数が整数でなくて実数ですが、「そのままの表記をLuaに渡せばよい」という点は変わらないためマクロ定義時の扱いは`\myRandom`と同じです。

```tex
\newcommand*{\mySqrt}[1]{% #1=‹x›
  \directlua{ my_sqrt(#1) }%
}
```

`my_sqrt`の実装は次のようになります。

```lua
  function my_sqrt(x)
    -- 固定小数点表記にするためstring.formatを通す
    tex.sprint(("%.7f"):format(math.sqrt(x)))
  end
```

これらを組み合わせれば完成です。完成版のコードには、`\mySqrt`の使用例として、「LaTeXの`\framebox`命令の引数に`\mySqrt`を使用することで、面積が1、2、3、4の正方形を順に出力する」ためのコードを載せました。

```text:test-8.tex
\documentclass{article}
\usepackage{luacode}
\begin{luacode*}
  function my_sqrt(x)
    tex.sprint(("%.7f"):format(math.sqrt(x)))
  end
\end{luacode*}
\newcommand{\mySqrt}[1]{%
  \directlua{ my_sqrt(#1) }%
}
\begin{document}
\setlength{\unitlength}{1cm}
\framebox(1,1){1}
\framebox(\mySqrt{2},\mySqrt{2}){2}
% ↑\framebox(1.4142136,1.4142136){2} と等価
\framebox(\mySqrt{3},\mySqrt{3}){3}
\framebox(2,2){4}
\end{document}
```

![code-08a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/e852af61-e682-f25e-197e-c8f43251a5c7.png)

### チョット注意しておく

ただし、今の`\myRandom`の実装には欠点があります。例えば、`\myRandom`の引数に99999を指定しようとして間違えて次のように書いてしまったとします。

```tex
\myRandom{99,999}% 間違い:余計なコンマがある
```

すると、次のような`\directlua`が実行されることになります。

```tex
\directlua{ my_random(99,999) }
```

`my_random(99,999)`はLuaの文法として正しいのでエラーにはなりません。第2引数の999は無視されるため、結局「1～99の範囲の乱数が出る」という意図しない結果になります。

とはいっても、LaTeX自体が元々**グダグダな世界**であり、「記述を間違えてもエラーにならずに意味不明な動作が起こる」という事例が日常的に起こっています。なので、この欠点についても**特に気にしない**ことにしましょう:upside_down:[^error-safe]

[^error-safe]: どうしても気になるようであれば、「引数を文字列として扱って（後述の方法で）Luaの関数に渡して、Luaの関数内で“適切な解読処理”を行う」という処置をすればいいでしょう。

もう少し深刻（？）な問題は、「引数の整数は10進表記の即値で与える必要があり、16進表記[^hex-latex]やカウンタ参照[^arabic]などの別の形式は受け付けられない」ということです。

[^hex-latex]: もっとも、整数の16進表記（`"26C4`のような表記）はLamport本では「`\symbol`命令の引数としての用法」としてしか現れないため、LaTeXの文法の体系の中にあるのかは微妙です。
[^arabic]: ちなみに、「10進表現しか受け付けない」引数に対してカウンタ参照をどうしても渡したいという場合は、`\arabic`命令を使うという手段があります。「`\directlua`の引数内で`\arabic{‹カウンタ名›}`を書いたらそれは当該カウンタの現在値の10進表記を書いたのと同等になる」という規則があるからです。

```text
\myRandom{42}% 10進表記, OK
\myRandom{"2A}% 16進表記, ダメ
\myRandom{\value{section}}% カウンタ参照, ダメ
```

しかし、少なくともLaTeXの範囲では10進表記以外の数値の表現は実際にはほとんど現れないのも確かです。従って、この点についても**​「そういう仕様である」と規定**しておけば十分でしょう。

### もっともっと引数してみる

これまでに述べた方針は、引数の数が増えた場合でも基本的に変わりません。例えば以下の例を考えましょう。

  * `\myRandomRange{下限m}{上限n}`： m～nの範囲の整数をランダムに選んでその10進表記を出力する。

引数が2つになったので、`#1`に加えて`#2`もLua関数に渡すだけです。

```tex
\newcommand*{\myRandomRange}[2]{% #1=‹下限m›,#2=‹上限n›
  \directlua{ my_random_range(#1, #2) }%
}
```

```lua
  function my_random_range(m, n)
    -- 実はmath.randomにも2引数の形式がある
    tex.sprint(math.random(m, n))
  end
```

完成版のコードには、`\myRandomRange`の使用例として、「LaTeXの`\symbol`命令と併用して、A～Zの英字をランダムに選んで出力する」ためのコードを載せました。

```text:test-9.tex
\documentclass[a4paper]{article}
\usepackage{luacode}
\begin{luacode*}
  function my_random_range(m, n)
    tex.sprint(math.random(m, n))
  end
\end{luacode*}
\newcommand*{\myRandomRange}[2]{% #1=‹下限m›,#2=‹上限n›
  \directlua{ my_random_range(#1, #2) }%
}
\begin{document}
% A～Zの英字がランダムに選ばれる.
Today's lucky letter is \symbol{\myRandomRange{65}{90}}.
\end{document}
```

![code-15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/17904295-58b2-0f1a-9fa3-3351c9425dc2.png)

オプション引数を扱う例も挙げておきます。

  * `\myYoubi[‹年›]{‹月›}{‹日›}`： 指定の年月日の曜日を漢字1文字で（“木”のように）出力する。年を省略した場合は現在の年とする。

LaTeXの`\newcommand`命令でオプション引数をもつマクロを定義する場合、必ず「オプション省略時のデフォルト値」を指定することになります。今の場合、無理に「LaTeXの側で現在年を取得しよう」などと頑張ったりせずに、「引数省略時はnilをLuaに渡して、あとはLuaの側で処理する」という方針をとります。要するに`#1`が`nil`になればいいので、`\myYoubi`の定義は以下のようになります。

```tex
\newcommand*{\myYoubi}[3][nil]{% #1=年;#2=月;#3=日
  \directlua{ my_youbi(#1, #2, #3) }%
}
```

Luaのコードでは`my_youbi()`の第1引数がnilの場合の処理を行います。

```lua
  -- 補助関数: y年m月d日の曜日を1～7で返す
  local function youbi(y, m, d)
    local t = os.time({year=y, month=m, day=d})
    return os.date("*t", t).wday
  end
  local chars = {"日", "月", "火", "水", "木", "金", "土"}
  -- オプション無しの \myYoubi の呼出ではyがnilになる
  function my_youbi(y, m, d)
    -- yがnilの場合はorの右辺の値が代入される
    y = y or os.date("*t", os.time()).year
    tex.sprint(chars[youbi(y, m, d)])
  end
```

完成版のコードではオプションがある場合とない場合の実行例を載せました（実行結果は現在年が2020年の場合）。

```text:test-10.tex
\documentclass[a4paper]{ltjsarticle}% 日本語なので
\usepackage{luacode}
\begin{luacode*}
  local function youbi(y, m, d)
    local t = os.time({year=y, month=m, day=d})
    return os.date("*t", t).wday
  end
  local chars = {"日", "月", "火", "水", "木", "金", "土"}
  function my_youbi(y, m, d)
    y = y or os.date("*t", os.time()).year
    tex.sprint(chars[youbi(y, m, d)])
  end
\end{luacode*}
\newcommand*{\myYoubi}[3][nil]{% #1=年;#2=月;#3=日
  \directlua{ my_youbi(#1, #2, #3) }%
}
\begin{document}
\begin{itemize}
\item 今年の8月8日は\myYoubi{8}{8}曜日です。
\item 2008年8月28日は\myYoubi[2008]{8}{28}曜日です。
\end{itemize}
\end{document}
```

![code-16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/a7b8b41e-1669-d06c-3c99-cd7be84eda1a.png)

※:sushi:TeX言語者向け補足：先ほど「Luaで実装したLaTeXマクロは完全展開可能になる」といいましたが、（`\newcommand`で）オプション引数付きで定義したマクロは例外になります。これはオプション引数の処理の部分が完全展開可能にならないからです。

### 数値以外の引数をどうにかする

引数の扱いに慣れてきたところで、いよいよ数値以外の引数について考えてみましょう。次のような単純な機能のマクロを例にして引数の扱いを説明します。

  * `\myRepeat{‹回数n›}{‹テキスト›}`： 指定のテキストをn回出力する。

まずは第2引数が“普通の文字列”である場合を想定して、マクロ`\myRepeat`をどう定義すべきかを考えましょう。例えば

```tex
\myRepeat{5}{Duck}
```

が実行されたとき、`\myRepeat`を処理するLua関数が受け取るべき引数は

```lua
my_repeat(5, "Duck")
```

となるはずです。Luaの文字列リテラルは`"`で囲まれているということを考えると、`\myRepeat`の定義は次のものでよいはずです。

```tex
\newcommand{\myRepeat}[2]{% #1=‹n›, #2=‹テキスト›
  \directlua{ my_repeat(#1, "#2") }%
}
```

`my_repeat`の実装は次のようになるでしょう[^string-rep]。

[^string-rep]: n回分の命令列を`string.rep`を使って作る方が簡単にみえますが、こうすると`txt`の末尾に命令がある場合に先頭の英字と不用意に繋がってしまう可能性があります。

```lua
  function my_repeat(n, txt)
    for i = 1, n do
      tex.sprint(txt)
    end
  end
```

この2つを組み合わせると、確かに`\myRepeat{5}{Duck}`は期待通りに動作します。

![code-17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/189c2980-d572-b1fe-6235-d1da2847d6c4.png)

さらに少し考えるとわかるように、この実装は引数のテキストが「LaTeXの特殊文字を含まない単なる文字列」である限りは、ほとんどの場合に通用します。唯一の例外は`"`を含む場合です。

```tex
\myRepeat{5}{A"B}
```

この場合、実行されるLuaコードは`my_repeat(5, "A"B")`となりますが、これは不正であり、Luaの文法に従うと、正しくするには`"`を`\`でエスケープする必要があります。

```lua
my_repeat(5, "A\"B")
```

実用上は、`"`などよりもむしろ「LaTeXの命令を書けるようにする」という要件の方が大事かもしれません。例えば

```tex
\myRepeat{5}{\"H\o\~g\k{e}!}
\myRepeat{3}{{\TeX} is \emph{evil}!! }
```

のように特殊文字やテキスト装飾の命令を使いたいかもしれませんし、あるいは「赤マフラーの**ゆきだるま**:snowman:をいっぱい出力したい」（素敵:blush:）ということで

```tex
\myRepeat{20}{\scsnowman[hat,snow,arms,muffler=red]}
```

を実行したいかもしれません。これらを実現するには、それぞれ次のようなLuaコードを実行する必要があります。

```lua
my_repeat(5, "\\\"H\\o\\~g\\k{e}!")
my_repeat(3, "{\\TeX} is \\emph{evil}!! ")
my_repeat(20, "\\scsnowman[hat,snow,arms,muffler=red]")
```

仮にこれらがLuaで実行されれば、確かに期待通りの動作になります。ここで問題なのは、**​「このコードは禁止文字を含むためそもそも \\directlua の中に書けない」​**ということです。

これはかなり致命的な問題のようにみえますが、幸いなことに、luacodeパッケージはこの問題を解決するための手段を提供しています。それが **\\luastringN 命令**[^luastringn]です。

[^luastringn]: ちなみに、`\luastringN`の“N”は“no-expand”（展開なし）という意味です。“N”のない`\luastring`という命令もあり、こちらは「展開あり」なのですが、既に述べたようにLaTeXユーザにとっては「展開」は理解不能なものなので`\luastring`には用はないでしょう。

```tex
\luastringN{テキスト}% 引数は命令を含んでいてもよい
```

LaTeXの範囲内でこの命令の動作を正確に述べるのは困難[^luastring-tex]なのですが、簡単にいうと、`\luastringN`はテキストを「Luaの文字列リテラル」に置き換えます。例えば：

  * `\luastringN{A"B}`と書くと、`"A\"B"`と解釈される。
  * `\luastringN{\"H\o\~g\k{e}!}`と書くと、`"\\\"H\\o \\~g\\k {e}!"`[^cmd-space]と解釈される。

そして重要なこととして、この**変換後の文字列はverbatimなものとして扱われる**ため、たとえ`\`のような特殊文字が入っていても`\directlua`の中に書いたときに常に“そのまま”読み取られます。

[^luastring-tex]: :sushi:TeX言語者向けの説明：`\luastringN{トークン列}`を完全展開すると、「引数のトークン列を展開せずに脱トークン化してできる文字列にLua文字列リテラルのエスケープを施した後に全体を`"…"`で囲った形の \\the-文字列」に展開されます。ちなみに、`\luastring`の方は、先の説明の「展開せずに」を「完全展開して」に変えた動作を行います。
[^cmd-space]: よく見ると、`\o`→`\\o␣`、`\k`→`\\k␣`のように空白文字が入ってますが、元々LaTeXの規則で`\o`と`\o␣`は同値であるので「空白がある方に“正規化”された」と考えればよいでしょう。

以上のことをまとめると、結局、LaTeXで

```tex
\directlua{ my_repeat(5, \luastringN{\"H\o\~g\k{e}!}) }
```

を実行するとLuaで

```lua
my_repeat(5, "\\\"H\\o \\~g\\k {e}!")
```

が実行されるということです。この`\luastringN`さえあれば、懸案だった`\myRepeat`の実装はいとも簡単に済んでしまいます。

```tex
\newcommand{\myRepeat}[2]{% #1=‹n›, #2=‹テキスト›
  \directlua{ my_repeat(#1, \luastringN{#2}) }%
}
```

これだけで、`#2`の中にどんな文字や命令が入っていても、「そのテキストを表すLua文字列」が関数に渡されるのです。（luacodeパッケージスゴイ:astonished:）

※`\directlua`の中の`\luastringN`の挙動はもう理解しているわけなので、「使用禁止文字の規則」の例外に`\luastringN{テキスト}`[^luastringn-arg]を追加しておきましょう:upside_down:

[^luastringn-arg]: ここで`\luastringN`の引数には「LaTeXのテキストとして妥当なもの」なら何でも（使用禁止文字を含んでいても）入れられることにも注意してください。

`\myRepeat`の完成版のコードは以下の通りです。使用例として「赤マフラーの**ゆきだるま**:snowman:をいっぱい出力する」を入れました（素敵:blush:）。

```text:test-11.tex
\documentclass[a4paper]{article}
\usepackage{xcolor,scsnowman}% ゆきだるま☃!
\usepackage{luacode}
\begin{luacode*}
  function my_repeat(n, txt)
    for i = 1, n do
      tex.sprint(txt)
    end
  end
\end{luacode*}
\newcommand{\myRepeat}[2]{% #1=‹n›, #2=‹テキスト›
  \directlua{ my_repeat(#1, \luastringN{#2}) }%
}
\begin{document}
\myRepeat{20}{\scsnowman[hat,snow,arms,muffler=red]}
\end{document}
```

![code-17a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/8e545124-221b-140c-0347-7d9a119ce641.png)

## イロイロつくってみた:muscle:

### LaTeX的FizzBuzz

FizzBuzzで「FizzやBuzzに置き換える」代わりに「数字を装飾する」としたものです[^nabeazz]。

  * `\myFizzBuzz{‹整数n›}{‹命令列1›}{‹命令列2›}`： 1～nまでの整数の10進表記を欧文空白区切りで出力する。`‹命令列1›`、`‹命令列2›`には宣言型[^declarative]のテキスト装飾命令を指定し、3の倍数のときには`‹命令列1›`、5の倍数のときには`‹命令列2›`が適用される。（両方に該当する場合は`‹命令列1›`、`‹命令列2›`の順に実行される。）

[^nabeazz]: なお、某NabeAzzはやめました。もう元ネタが忘れ去られていると思われるので:upside_down:
[^declarative]: つまり、`\textbf`や`\textcolor{red}`ではなく`\bfseries`や`\color{red}`の方を指定するということです。

```text:test-12.tex
\documentclass[a4paper]{article}
\usepackage{xcolor,luacode}
\begin{luacode*}
  function my_fizzbuzz(n, cmd3, cmd5)
    for i = 1, n do
      tex.sprint((i == 1) and "{" or " {") -- 区切り空白
      if i % 3 == 0 then tex.sprint(cmd3) end
      if i % 5 == 0 then tex.sprint(cmd5) end
      tex.sprint(tostring(i).."}")
    end
  end
\end{luacode*}
\newcommand{\myFizzBuzz}[3]{%
  % とにかく \luastringN を使えばOK
  \directlua{ my_fizzbuzz(#1, \luastringN{#2}, \luastringN{#3}) }%
}
\begin{document}
% 3の倍数は太字イタリック, 5の倍数は赤色になる
\myFizzBuzz{100}{\bfseries\itshape}{\color{red}}
\end{document}
```

![code-18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/c868affe-5035-2cc7-30bd-b7650f67ce02.png)

### 漢数字変換

よくあるネタ:smiley:

  * `\myKansujiOf{‹整数n›}`： 整数nを十字方式（数の日本語での読みの漢字表記）で出力する。※ただしnは0～0x7FFFFFFFの範囲に限る。
  * `\myKansuji{‹カウンタ名›}： `\myKansujiOf`の形式で出力するカウンタ出力命令[^counter-cmd]。

[^counter-cmd]: 「カウンタ出力命令」とは、`\arabic`や`\roman`や`\Alph`のように、カウンタ名を引数にとってカウンタの現在値を特定の形式で出力する命令のことを指します。

※:sushi:Luaで実装したので完全展開可能になることに注意。カウンタ出力命令は原則的に完全展開可能性が必要なのでTeX言語で実装するのは極めて困難なことが多いのですが、Luaだと勝手に完全展開可能性が得られます:upside_down:

```text:test-13.tex
\documentclass[a4paper]{ltjsarticle}% 日本語なので
\usepackage{luacode}
\begin{luacode*}
  local kds = {"一","二","三","四","五","六","七","八","九"}
  kds[0] = ""
  local function digit(j, km)
    if j >= 2 then tex.sprint(kds[j]) end
    if j >= 1 then tex.sprint(km) end
  end
  local function block(j, kbm)
    digit(j // 1000, "千")
    digit(j // 100 % 10, "百")
    digit(j // 10 % 10, "十")
    tex.sprint(kds[j % 10])
    if j > 0 then tex.sprint(kbm) end
  end
  function my_kansuji_of(n)
    if n == 0 then tex.sprint("〇")
    elseif 1 <= n and n <= 0x7FFFFFFF then
      block(n // 100000000 % 10000, "億")
      block(n // 10000 % 10000, "万")
      block(n % 10000, "")
    end -- 範囲外は何も出力しない
  end
\end{luacode*}
\newcommand{\myKansujiOf}[1]{% #1=‹整数n›
  \directlua{ my_kansuji_of(#1) }%
}
\newcommand{\myKansuji}[1]{% #1=‹カウンタ名›
  \myKansujiOf{\arabic{#1}}% \value でなく \arabic を使う
}
\begin{document}
% 節番号の出力形式を漢数字にする
\renewcommand{\thesection}{\myKansuji{section}}
\setcounter{section}{10098}% 10099節から開始

\section{\TeX}\label{sec:tex}
\myKansujiOf{800}屋 % 特に意味はありません;-)

\section{\LaTeX}\label{sec:latex}
\myKansujiOf{40010}川 % 特に意味はありません;-)

\section{まとめ}
\ref{sec:tex}節と\ref{sec:latex}節はアレ。
\end{document}
```

![code-19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/f4edb11f-377e-4774-3d7b-48f795f70606.png)

### マフラーの色を少しずつ変えていく

素敵:blush:

  * `\mySnowmanRow{‹整数n›}{‹色1›}{‹色2›}`： n個の**ゆきだるま**:snowman:の列を描く。マフラーと帽子の色について、左端は`色1`、右端は`色2`にして、その間のものはグラデーションにする。

```text:test-14.tex
\documentclass[a4paper]{article}
\usepackage{xcolor,scsnowman,luacode}% ゆきだるま☃!
\begin{luacode*}
  local prm = "\\scsnowman[scale=1.5,snow,arms,hat=%s,muffler=%s]"
  function my_snowman_row(n, lclr, rclr)
    for i = 1, n do
      local clr = ("%s!%.1f!%s"):format(
          lclr, (n - i) / (n - 1) * 100, rclr)
      tex.sprint(prm:format(clr, clr))
    end
  end
\end{luacode*}
\newcommand{\mySnowmanRow}[3]{%
  \directlua{ my_snowman_row(#1, \luastringN{#2}, \luastringN{#3}) }%
}
\begin{document}
\mySnowmanRow{10}{red}{blue}
\end{document}
```

![code-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/9b2a4199-980f-4f24-e78a-b13b4682bd15.png)

## まとめ

TeX言語を知らない幸せなLaTeXユーザ:blush:でも、**Luaを活用すれば複雑なマクロをつくれます！** ただしその際は、自分の知らない**TeX言語:scream:からは徹底的に逃げ回る**ように心がけましょう！