マクロツイーター

はてダから移行した記事の表示が崩れてますが、そのうちに直せればいいのに(えっ)

BXjscls の新しいやつ(v1.7c)

CTAN での最新版は 1.8 版で、W32TeX ではこの版が収録されている。

しかし、TeX Live でこの版(以降)が収録されるのは 4 月末リリース予定の 2018 からであり、TeX Live 2017 最終版の BXjscls は 1.7c 版である。そこで、まずは 1.7a → 1.7c 版の変更点を述べることにする。

upLaTeX でも LuaLaTeX でも源ノ書体する話(jafont の“括弧付き指定”)

例えば、「Source Han の OTC 版」のフォントを使うことを BXJS クラスで指定したい場合、もしエンジンが upLaTeX であれば、pxchfon パッケージでのプリセット名は sourcehan-otc なので、クラス宣言は次のようになる。

% upLaTeX
\documentclass[uplatex,dvipdfmx,ja=standard,jafont=sourcehan-otc]{bxjsarticle}

ところが、エンジンが LuaLaTeX の場合は、luatexja-preset パッケージでのプリセット名は sourcehan なので、次のようなクラス宣言が必要である。

% LuaLaTeX
\documentclass[lualatex,ja=standard,jafont=sourcehan]{bxjsarticle}

従って、autodetect-engine を使う必要がある場面は、jafont で「Source Han の OTC 版」を指定することができなず、不便である。

もちろん、こういうことが起こらないように、pxchfon と luatexja-preset の仕様においてプリセット名を一致させておくのが望ましいのであるが、sourcehanについては、以下のような事情がある。

  • LuaLaTeX では、使用するフォントをフォント名で指定できる。
  • Source Han フォントには OTC 版と OTF 版があるが、この 2 つは“同じフォント”なので同じフォント名をもつ。従って、luatexja-preset ではこの 2 つの版を同じ設定とみなすことができて、単一のプリセット名 sourcehan で両方に対応できる。
  • ところが、(u)pLaTeX + dvipdfmx においては、フォントはファイル名で指定する必要がある。
  • OTC 版と OTF 版はファイル名が異なるため、pxchfon では両者は別の設定として扱わざるを得ない。なので、OTC 版は sourcehan-otc、OTF 版は sourcehan と別のプリセット名になる。
  • 結果的に、OTC 版と OTF 版の一方はプリセット名が食い違うことを避けられない。

こういう事態への(かなり姑息な)解決法として、jafont の書式について次のような特殊な規則を設けることにした。

  • jafont に与える値を“sourcedhan(-otc)”のように一部を(一か所だけ)括弧で囲むことができる。
  • エンジンが XeLaTeX/LuaLaTeX の場合は、「括弧内を無視した文字列」、つまり“sourcehan”を実際の値として使う。
  • それ以外の場合は、「括弧自体を無視した文字列」、つまり“sourcehan-otc”を実際の値として使う。

つまり、autodetect-engine する場合に「Source Han の OTC 版」を指定したい場合は次のように書くことができる。

% エンジンはなんでも; UTF-8
\documentclass[autodetect-engine,dvi=dvipdfmx,ja=standard,jafont=sourcehan(-otc)]{bxjsarticle}
\begin{document}
☃はいいぞ。
\end{document}

(u)pLaTeX 以外で zw できる話(units 和文パラメタ)

標準(standard)和文ドライバの和文パラメタなので、次のように指定する。

\documentclass[ja=standard,japaram={units,(他パラメタ)},(他オプション)]{bxjsarticle}

units を指定すると、(u)pLaTeX 以外のエンジンでも「和文用の単位」(zwzh(true)Q(true)H)を使えるようになる。

% LuaLaTeX; UTF-8
\documentclass[lualatex,ja=standard,japaram={units},a4paper]{bxjsarticle}
\begin{document}
\fbox{\parbox{10zw}{%
{\TeX}言語は超絶\hspace{2zw}で危険、
\hspace{6zw}}}
\end{document}
注意事項
  • LaTeX の全ての長さ指定でサポートされるわけではない。和文単位が使えるのは以下の箇所である。
    • calc パッケージの長さ数式に対応している箇所。
    • 実は LaTeX 標準(カーネル)の機能では一部 calc の数式が使えない箇所(\hspace 命令など)が残っているが、それも calc に対応する動作に変更されるため、和文単位が使えるようになる。
  • 当然であるが、TeX 言語での寸法指定の書式は何も変わらない。
  • zwzhの実際の値は以下のようになる。
    • (u)pLaTeX では元来の定義通り。
    • LuaLaTeX では LuaTeX-ja の \zw/\zh と同じになる。
    • それ以外の場合は、両者ともに \jsZw(規約上の全角幅((LuaLaTeX 以外(かつ nozw 非指定)では、\zw\jsZw と同じ意味で定義されている。)))と同じになる。
bxcalc パッケージ

units パラメタの機能は、BXcalc バンドルの機能を利用して実装されている。BXcalc は次のような構成になっている。

  • bxcalc パッケージ: bxcalcux と bxcalcize の両方を読み込む。
  • bxcalcux パッケージ: calc の長さ数式でカスタムの新しい単位を使えるようにする。
  • bxcalcize パッケージ: LaTeX の標準の機能における全ての長さ指定を calc に対応させる。

bxcalc の役割は本来は他の 2 つのパッケージを読み込むことだけであるはずだが、現状では暫定的に((BXjatool の再編成が完了したときには、\usepTeXunits の機能はその中に含められる予定で、その場合、\usepTeXunits は非推奨になる可能性があるが廃止はされない。))次の命令を用意している。

  • \usepTeXunits:[命令] 和文用の単位を bxcalcux の機能を利用して定義する。
    ※(u)pTeX エンジンでは提供されない。

つまり、BXJS クラスで units 和文パラメタが指定された場合、「エンジンが (u)pLaTeX 以外であれば bxcalc を読みこんで \usepTeXunits を実行する」という動作を行っているわけである。bxcalc パッケージは CTAN に登録されていて TeX Live に収録済であるので、その機能を用いることで簡単に「(u)pLaTeX 以外で和文単位を使える」設定が可能になる。

補足:BXjatool バンドル/bxjacalcux パッケージとの関係

以前の記事で「LuaTeX-ja で和文単位を使う」ための“BXjatool バンドルの bxjacalcux パッケージ”を紹介したことがある。この bxjacalcux は先述の「bxcalc パッケージ + \usepTeXunits 命令」とほぼ等価なものである。

当該の記事を書いた当時は bxcalcux と bxcalcize が BXjatool に入っていたが、メンテナンスの都合のためにこれらを分離して作ったのが BXcalc バンドルである。bxjacalcux は現在も BXjatool に残っていて、BXcalc バンドルと組み合わせて使用できる。

節カウンタ書式をフツーにする話(label-section オプション)

jsclasses に潜んでいるある問題点を解決するためのもの。

前提知識:カウンタ書式指定とカウンタラベル

bxjsbook クラス(および大抵の和文 book 系クラス)では、章見出しにおいて章の番号が「第2章」のように出力される。一方で、節番号「2.1」の中に現れる章番号は単に「2」となっている。

この状態を実現する場合、章(chapter)と節(section)のカウンタ書式(\thechapter\thesection)はどう定義されているべきであろうか。

\newcommand{\thechapter}{\arabic{chapter}}
\newcommand{\thesection}{\thechapter.\arabic{section}}

もちろんこれでは節番号が「第2章.1」となってしまうので不適切である。

\newcommand{\thechapter}{\arabic{chapter}}
\newcommand{\thesection}{\arabic{chapter}.\arabic{section}}

これは見かけ上は正しくなるが問題がある。「節番号の中の章番号」の表記は当然章番号の表記を踏襲すべきであり、独自に(\arabic{chapter} のように)決めるべきではないからである。実用上でも、例えば、付録(\appendix 以後)では章番号の表記が英大文字(\Alph{chapter})に変更されるため、上記のような定義では節番号の表記が不正になってしまう。

ではどうするのが正しいかというと、章の「カウンタの書式」(\thechapter)は単に「2」(付録では「B」)のように番号だけにすべきであり、章見出しにおいて「第2章」(付録では「付録B」)のように前後に語句を補う(以後、これを章の「カウンタラベル」と呼ぶことにする)のは、章見出しの出力処理の方に任せるべきなのである。

\newcommand{\thechapter}{\arabic{chapter}}% "第"や"章"はここには入れない
\newcommand{\thesection}{\thechapter.\arabic{section}}

このように、文書クラスのカウンタ書式を設計する場合は、「カウンタ」と「カウンタラベル」の役割を明確に区別することが必要である。\theXXX 命令が表すのは「カウンタ」の書式である。

前提知識:箇条書きの項番号

「カウンタ」と「カウンタラベル」の区別の例として、箇条書きの項番号を見てみよう。

このように、BXJS クラス(や他の多くのクラス)では 1 段目の番号付箇条書きの番号(enumi カウンタ)は「1.」のように出力されているが、これは「カウンタラベル」の書式である。「カウンタ」の書式、すなわち \theenumi の定義は数字しかない。*1

\newcommand{\theenumi}{\arabic{enumi}}

項番号を \ref 命令で参照した場合に出力されるのは「カウンタ」の方である。(章番号の場合は、著者が「\ref{chap:foo}章」のように語句を補って書く。)

特筆すべきこととして、箇条書きについては「カウンタラベル」の方もマクロになっていて書式の変更が可能になっている。例えば、enumi のカウンタラベル \labelenumi は次のように定義されている。

\newcommand{\labelenumi}{\theenumi .}
jsclasses の節のカウンタ書式がアレ

jsarticle クラスは(他の article 系クラスの多くと異なり)付録中において節見出しに「付録」の語句を出力する。

jsarticle での \thesection\thesubsection の定義は以下のようになっている。

% \appendix の前では
\newcommand{\thesection}{\arabic{section}}
\newcommand{\thesubsection}{\arabic{section}.\arabic{subsection}}
% \appendix の後では
\newcommand{\thesection}{付録\Alph{section}}
\newcommand{\thesubsection}{\Alph{section}.\arabic{subsection}}

これは先に挙げたアンチパターンになっていることが判るだろう。(節見出しの部分以外での節番号の出力に「付録」をつけない方針である限りは)「付録」の語句は「カウンタラベル」の書式に属するものであり、「カウンタ」の定義(\thesection)には本来含まれるべきではないのである。アンチパターンの副作用として、小節番号中の節番号を \thesection で継承することができなくなり、仕方がないので、\thesubsection の定義も \appendix の処理中で変更している。

これで問題が起きなければ「バッドノウハウが成功した」ということになるが、世の中はそんなに甘くない。例えば、次のような定理型環境の定義を行ったとする。

\newtheorem{truth}{真理}[section]

LaTeX 標準では section を従属カウンタとする定理型環境のカウンタ書式は次のように定義される。

\newcommand{\thetruth}{\thesection.\arabic{truth}}

この挙動は jsarticle でも変わらないが、jsarticle では \thesection は「カウンタ書式としては不適切」である。結局、付録の中で truth を使うと次のような残念な結果になってしまう。

これが \newtheorem だけの問題であれば、\newtheorem の方に手を入れることで回避できる可能性もあるだろう。 しかし \thesection の機能に依拠する他の機能においても同様の問題が発生することは想像に難くない。 「カウンタとカウンタラベルは区別すべき」という原則に帰らない限り解決できないのは明らかであろう。

label-section オプション

そういうわけで、BXJS では「付録」等の“付加語句”の扱いについて、原則に従った新しい実装を提供する。ただし、新しい実装は従来のもの(および jsclasses)と互換性がないので既定にせず、オプションで選択する方式をとる。

  • label-section=compat:(既定) jsarticle と同じ方式。
  • label-section=modern: 以下で説明する新しい方式。
  • label-sectoin=none: 節への語句の付加を抑止する。欧文や和文の標準クラスと同等になる。
modern なやり方

label-section=modern では以下の点を jsarticle の挙動から変更する。

  • 節のカウンタ書式(\thesection)は以下のように、\pre/postsectionname\appendixname(=“付録”)などの“付加語句”を含まない定義になる。

    % \appendix の前では
    \newcommand{\thesection}{\arabic{section}}
    % \appendix の後では
    \newcommand{\thesection}{\Alph{section}}
    
  • 小節のカウンタ書式(\thesubsection)は以下の通りで \appendix により変更されない。

    \newcommand{\thesubsection}{\thesection.\arabic{subsection}}
    

    \thesection が“付加語句”を含まないため、\thesubsection も含まない。

  • 同様に、\thesection を定義中に含む他のカウンタ書式も、“付加語句”を含まないことになる。

  • 以上の規定・性質は和文・欧文標準クラスのものと同等である。

  • 節のカウンタラベル書式は以下のものとする。

    % \appendix の前では
    \presectionname\thesection\postsectionname
    % \appendix の後では
    \appendixname\thesection
    

    jsarticle において \thesection が使われていた箇所では、代わりに上記のカウンタラベル書式が使われる。

  • 小節以下のレベルのカウンタラベル書式はカウンタ書式と一致させる。当然“付加語句”は含まれない。

上記の仕様から導出される挙動はほとんどがユーザの期待に沿うものになると思うが、以下の点について注意が必要である。

  • 節番号を \ref で参照した場合、jsarticle と異なり、その出力には“付加語句”(付録)は含まれない。ユーザが“付録\ref{sec:Duck}”のように書く必要がある。(標準クラスと同じ。)
  • jsarticle では \appendix 命令が“付加語句”のマクロの定義を変更する以下の動作を行う:
    • \presectionname\appendixname と同値にする。
    • \postsectionname を空テキストに再定義する。
    新しい方式ではこの変更は行われない。
カウンタラベル書式をカスタマイズできる話

先述の箇条書きのカウンタラベル書式マクロ \labelenumi と全く同じ方式で、節のカウンタラベル書式を \labelsection というマクロで再定義できる。

% LuaLaTeX; UTF-8
\documentclass[lualatex,ja=standard,
  label-section=modern,% モダーン!
  a4paper]{bxjsarticle}
%↓カウンタラベル書式を変えちゃうよ
\renewcommand{\labelsection}{§\thesection}
\newtheorem{truth}{真理}[section]
\begin{document}

\section{ゆきだるま}
\subsection{キホン的性質}
\begin{truth}
ゆきだるまは非アレである。
\end{truth}

\appendix %以下付録
%%↓もし付録中のカウンタラベル書式を変えたいなら自分で変えよう
%%\renewcommand{\labelsection}{☆\thesection}
\section{アヒル}
\begin{truth}
アヒルのアレ性は不可知である。
\end{truth}

\end{document}

以下は補足事項。

  • 既定の \labelsection の定義は先に「カウンタラベルの書式」として説明した通りのテキストであり、これは \appendix 命令により自動的に出力が変わる。((実はこの場合も内部マクロを間に挟んでいるので、\labelsection 自体が再定義されているわけではない。))しかし、もし \labelsection をユーザが再定義した場合は、それは \appendix により再定義されることはない。
  • 既定の \labelsection の定義は \pre/postsectionname\appendixname などの語句マクロを参照する。ユーザが再定義した後もそうであるかは当然定義内容に依る。
  • 実は、小節・小々節のカウンタラベル書式をカスタマイズ可能であり、マクロ \labelsubsection/\labelsubsubsection を定義(\newcommand)するとそれがカウンタラベル書式として使われる。既定では未定義でありこの場合はカウンタ書式と同一と見なされる。

*1:以降で実際のクラスにおける書式マクロの定義を挙げる場合、それは「実際の挙動と等価なものを LaTeX の文法で表したもの」を意味するものとする。実際のコードそのものではないことに注意。