BXghost: (u)pTeX 以外でも適切に和欧文間スペースを入れたい

2019-10-31 (updated: 2020-03-08)  #LaTeX 

今日はハロウィンですね.というわけでハロウィンとはサッパリまったく関係のない「ゴースト」の話をしたいと思います.

TL;DR

和欧文間スペース (xkanjiskip) がデフォルトで適切に挿入されない状況下で有用な「ゴースト」の挿入を行う PXghost を拡張し,(u)pTeX に加えて LuaTeX や XeTeX でも利用可能になった BXghost パッケージをリリースしました:

対応 TeX エンジンが増えていることを除き,このパッケージの使い方は PXghost とまったく同一です.なお BXghost は日本語組版を行うために開発されたものなので,(u)pTeX 以外のエンジンでは日本語組版のために必要なパッケージはユーザの手によって予め適切に読み込まれていることを仮定します1

これまでのあらすじ

pTeX で和欧混植を行う場合,特に何もしなくても多くのケースでは和文文字と欧文文字の間には和欧文間スペース (xkanjiskip) が適切に挿入されます.しかし,pTeX のバグや仕様の関係のために,本来であれば和欧文間スペースが挿入されて欲しい箇所に,スペースが挿入されない場合があります.

具体例として,次のような pLaTeX 文書を考えます2

%#!platex
\documentclass{jsarticle}
\begin{document}
\begin{flushleft}
ワタシハLinuxチョットデキル \\
ディレクトリ\texttt{/usr/}は「ユーザ」じゃない!
\end{flushleft}
\end{document}

これを通常の手順で pLaTeX で処理すると,最終的な出力は次のようになります:

pTeX でうまく和欧文間スペースが入らない例

1行目の “Linux” は普通の英文字列なので問題ないですが,2行目の “/usr/” は始まりと終わりがスラッシュ (/) という記号のため和欧文間スペースが入っていません.しかし,実際にはここは和欧文間スペースを入れたいところです3

このような場合の対処策として,ZR さんが PXghost というパッケージを開発されました.このパッケージを読み込むと,次の2つの命令が定義されます:

  • \eghostguarded{<text>}: 和欧文間スペースの挿入可否判断の際に,<text> が英文文字の列として扱われる
  • \jghostguarded{<text>}: 和欧文間スペースの挿入可否判断の際に,<text> が和文文字の列として扱われる

上記の例では /usr/ が英文文字の列として扱われなかったために和欧文間スペースが入っていませんでした.そこで,その部分を PXghost の \eghostguarded 命令で包んでみます.

【入力】

%#!platex
\documentclass{jsarticle}
\usepackage{pxghost}
\begin{document}
\begin{flushleft}
ワタシハLinuxチョットデキル \\
ディレクトリ\eghostguarded{\texttt{/usr/}}は「ユーザ」じゃない!
\end{flushleft}
\end{document}

【出力】

PXghost でうまく和欧文間スペースが入った例

今度はうまく和欧文間スペースが入りました.

このしくみは実はとても単純です.\eghostguarded{<text>}<text> の前後に「欧文ゴースト」すなわち「不可視かつ幅ゼロの欧文文字」4を挿入しています.欧文ゴーストは人の目には見えませんが,TeX はそれを英文文字として認識するため,その前後に和文文字がある場合は和欧文間スペースが挿入されます(前後に和文文字以外のものがある場合は余計なスペースを挿入しません).

同様に \jghostguarded{<text>}<text> の前後に「和文ゴースト」5を挿入することによって <text> が和文文字の列として振る舞うようにしています.

さらに多くの問題発生例や PXghost の原理・応用については,日本 TeX 界の有名人たちによって詳細な記事が書かれていますので,未読で興味のある方はぜひ一度読んでみてください:

(u)pTeX 以外ではどうなのか

PXghost は単機能ながらとても便利で,個人的には ZR 氏の開発する PX シリーズの中ではルビ振りの PXrubrica と並んでお気に入りのパッケージです.しかし,PXghost は PX の接頭辞が表すとおり (u)pTeX 専用のパッケージなので7当然他のエンジンでは使用できません.最近では LuaTeX を利用して日本語組版を行う機会も増えていますが,そうした (u)pTeX 以外のエンジンでは同様の問題は起こらないのでしょうか?

さっそく試してみようということで,先ほどの例を bxjscls を利用するように改変して様々な TeX エンジンで組版できるようにします.

【汎用の入力】

%#!ナンチャラlatex
\documentclass[autodetect-engine,dvi=dvipdfmx,ja=standard]{bxjsarticle}
\begin{document}
\begin{flushleft}
ワタシハLinuxチョットデキル \\
ディレクトリ\texttt{/usr/}は「ユーザ」じゃない!
\end{flushleft}
\end{document}

そして,この文書を実際に様々な TeX エンジンで組版します.蛇足ですが llmk というビルドツールを使うと上記ソースの ナンチャラlatex の部分を pdflatex, xelatex, lualatex 等々に書き換え

$ llmk <file>

とコマンドを叩くだけで指定した TeX エンジンを使用しつつ一発で最終的な PDF 出力を得られます.便利ですね.

【LuaTeX の出力】

LuaTeX でうまく和欧文間スペースが入らない例

まずは LuaTeX の出力を確認しています.LuaTeX では bxjsarticle は自動的に LuaTeX-ja を読み込みます.LuaTeX-ja を用いる限り LuaTeX では pTeX 系列に匹敵するクオリティの日本語組版が実現できるため,当然 “Linux” 前後には和欧文間スペースが入っています.一方で “/usr/” 前後は pTeX と同じく和欧文間スペースが入っていません.

【XeTeX の出力】

XeTeX でうまく和欧文間スペースが入らない例

XeTeX の日本語組版サポートは,残念ながら現状 pTeX や LuaTeX ほどには充実しているとは言えませんが,それでも bxjsarticle が自動的に読み込む xeCJK + ZXjatype のおかげで “Linux” のような通常の英文文字列と和文文字の境界には和欧文間スペースが挿入されます.“/usr/” 前後は例によって和欧文間スペースが入っていません.

【pdfTeX の出力】

pdfTeX でうまく和欧文間スペースが入らない例

pdfTeX ではどのようなシチュエーションにせよ和欧文間スペースは入りません.pdfTeX については,そもそも上記のエンジン汎用 LaTeX ソースがエラーなく通って「それっぽい出力」が得られるという事実が驚異的なのであって,およそマトモな日本語組版は不可能だと思っておいた方がよいでしょう.

以上から,少なくとも LuaTeX, XeTeX については (u)pTeX と同様「和欧文間スペースを挿入する能力があるが,時としてゴーストを用いた調整が必要な場面がある」という状況にあることがわかります.

BXghost の使い方

(u)pTeX 以外でも PXghost 相当の機能が使えると便利そうということで,PXghost を LuaTeX および XeTeX でも利用できるように拡張した BXghost パッケージを作りました.BXghost は (u)pTeX でももちろん利用できます8

対応エンジンが増えたと言うだけで,使い方は PXghost とまったく同じです.(u)pTeX 以外のエンジンを用いるときは間違えずに BXghost を読み込んでください.下記は具体的な使用例です.

【汎用の入力】

%#!ナンチャラlatex
\documentclass[autodetect-engine,dvi=dvipdfmx,ja=standard]{bxjsarticle}
\usepackage{bxghost}% pxghostの代わりにbxghostを読み込む
\begin{document}
\begin{flushleft}
ワタシハLinuxチョットデキル \\
ディレクトリ\eghostguarded{\texttt{/usr/}}は「ユーザ」じゃない!
\end{flushleft}
\end{document}

どのエンジンの出力結果もだいたい同じなので,ここでは LuaTeX での出力を載せておきます.

【LuaTeX の出力】

LuaTeX+BXghost でうまく和欧文間スペースが入った例

めでたく “/usr/” の前後にも和欧文間スペースが入りました🎉

オマケ:「(La)TeX のコマンド」を適切に組版しよう

(La)TeX の解説文書を作ろうとして「(La)TeX のコマンド」(バックスラッシュから始まるアレ)を紙面に印字したい場合を考えます.これをナイーブにやろうとすると,まさに和欧文間スペースが適切に入らないケースにハマります.

\verb を使う方法

LaTeX でバックスラッシュを含むような文字列を,単純に出力しようと思うと \verb を使おうとなるのが普通でしょう.実際にやってみましょう(例文の出典).

【入力】

朝起きがけの\verb|\expandafter|が気持ちのいい季節になりました。

【出力】

ナイーブに \verb を使うと和欧文間スペースが適切に入らない

“\expandafter” の後ろには和欧文間スペースが入っているのに,前には入らないという極めて中途半端で不格好な出力結果となってしまいました.

もちろん \eghostguarded を用いて \verb|\expandafter| 部分を「欧文文字列扱い」できればいいのですが,ご存知の通り \verb呪われた命令であるため他の命令の引数内で使うことはできません.したがって,次のように \verb|\expandafter| を単純に \eghostguarded の引数に入れることはできません

% これではうまくいかない!
朝起きがけの\eghostguarded{\verb|\expandafter|}が気持ちのいい季節になりました。

ではどうすればいいかというと「\verb の前後に欧文ゴーストで保護された空文字列を置いてやる」ことによって,意図する挙動を得ることができます9

【入力】

朝起きがけの\eghostguarded{}\verb|\expandafter|\eghostguarded{}が気持ちのいい季節になりました。

【出力】

\eghostguarded でハックすると一応うまくいく

ひとまずうまくいきましたが,\verb を使うたびに前後に \eghostguarded{} を書くのは面倒です.「呪い」のために \eghostguarded{}\verb|<text>|\eghostguarded{} という「定形」全体をコマンド化することもできません.

そのため個人的には,「(La)TeX のコマンド」出力のためには専用のコマンドを用意する方法をおすすめしています.

BXghost の verb オプションで解決!(2020-02-27 追記)

先月リリースした新しい BXghost (v0.3.0) にはパッケージオプション verb が追加されました.これを用いると,\verb の定義が上書きされて \eghostguarded で保護された状態になります.

\usepackage[verb]{bxghost}
\begin{document}
朝起きがけの\verb|\expandafter|が気持ちのいい季節になりました。
\end{document}

verb オプションを使うと簡便

ただしこのオプションは LaTeX の基本的なコマンドである \verb を上書きするものなので,それに起因するトラブルに見舞われる可能性がゼロではないので注意してください10.また,オプションの性質上すべての \verb を欧文文字列として扱うようにするものなので,\verb の中に欧文文字列扱いすべきでない要素(例えば和文文字)が,特に先頭末尾において,現れる可能性がある文書では配慮が必要でしょう.

専用のコマンドを定義する方法

まずやりたいこととしては,\cmd{command} と書くとタイプライタ体で “\command” と印字されるようなコマンドを定義したいです.テキストモードでは \textbackslash を使うとバックスラッシュを出力できることを知っていれば,次のように書きたくなるかもしれません(実際この方法を使っていると思われる (La)TeX の解説文書をよく目にします):

【入力】

朝起きがけの\texttt{\textbackslash expandafter}が気持ちのいい季節になりました。

【出力】

\textbackslash を使うと和欧文間スペースは入るが書体がおかしい

バックスラッシュの前にも和欧文間スペースが入り,一見うまくいっているようですが,残念ながらバックスラッシュの書体だけが他の文字と異なり浮いて見えてしまいます11

バックスラッシュも他の文字と同じタイプライタ体で出力したい場合は \symbol 命令を用います12.この命令は \symbol{<number>} のように用いて文字コード <number> の文字を単純に出力します.

【入力】

朝起きがけの\texttt{\symbol{92}expandafter}が気持ちのいい季節になりました。

【出力】

\symbol でもやはり和欧文間スペースが入らない

ナイーブに \verb を使ったときと同じ状況(“\expandafter” の前だけ和欧文間スペースが入っていない)になりましたが,今度は「呪われた命令」が含まれていないので \eghostguarded で囲うことができ,またコマンド化することも可能です.

【入力】

\newcommand{\cmd}[1]{\eghostguarded{\texttt{\symbol{92}#1}}}
朝起きがけの\cmd{expandafter}が気持ちのいい季節になりました。

【出力】

\eghostguarded で円満解決

完璧ですね.今度から「(La)TeX のコマンド」を組版したいときはぜひこの \cmd コマンドを活用してみてください.そして,じゃんじゃん LaTeX の解説文書を書きましょう!


  1. 2019年9月現在,具体的には LuaTeX においては LuaTeX-ja,XeTeX においては bxjscls の使用が前提になります. ↩︎

  2. 元ネタは「ワタシハリナックスチョットデキル」(全部カタカナ表記)です.また /usr ディレクトリの由来は諸説あります. ↩︎

  3. 例えば url パッケージ\url 命令でスラッシュで終わる URL を和文文字列内に挿入した場合は適切に和欧文間スペースが入ります.ちなみにですが,同じ \url という名前の命令でも hyperref パッケージhidelinks オプションを使用している場合はスラッシュ直後に和欧文間スペースが入らないようです. ↩︎

  4. その正体は PXghost/BXghost では “compound word mark” と呼ばれる特殊な記号です. ↩︎

  5. PXghost/BXghost の和文ゴーストは大雑把に言うと「空白スペースを出力し,直後に 1zw(すなわち和文文字1文字分の幅)戻る」ことで実現しています. ↩︎

  6. この記事にある \hbox の例と siunitx の例は,その後の(おそらく pTeX 側の?)修正のおかげで最新の TeX Live 2019 ではいずれも再現しません(PXghost を使わなくても適切に和欧文間スペースが入ります). ↩︎

  7. ZR さん作のプロダクトは接頭辞を見ると対応パッケージがわかります.基本的には PX シリーズは pTeX 専用,ZX シリーズは XeTeX 専用,BX シリーズは様々なエンジン対応です(参考). ↩︎

  8. ApTeX (pTeX-ng) という (u)pTeX の拡張エンジンに対しても pTeX と同じロジックが通用したので,特別なことはしていませんがサポート対象ということにしています. ↩︎

  9. この例だと「欧文ゴースト」が \verb|\expandafter| 前後に2つずつ入ることになりますが,連続する欧文文字(ゴーストを含む)の間にはもちろん和欧文間スペースが挿入されることはないので,最終的な見た目としては “\expandafter” の前後に適切な大きさの和欧文間スペースが入ることになります. ↩︎

  10. doc パッケージなど LaTeX カーネルの \verb の定義を上書きするパッケージが複数ある,shortvrb パッケージの \MakeShortVerb が対応しているのが \verb だけで他を指定できない,などの事情があり,やむを得ずカーネル命令の定義を上書きするようなデザインとなりました.なお BXghost を verb オプション有効で用いる場合は \verb を再定義する他のパッケージよりも後に読み込まないと機能が有効にならない可能性があるため,なるべく最後の方で読み込むようにしてください. ↩︎

  11. LaTeX の \textbackslash 命令の「仕様」について明確なドキュメントを私は見たことがないのですが(LaTeX2e で追加されたコマンドのためランポート本にも言及がありません),挙動と実装を見る限りデフォルトでは常に一定の書体 (OMS/cmsy/m/n) で出力されることが意図されているようです. ↩︎

  12. TeX 言語者向けの情報:\symbol 命令は LaTeX 版の \char です.TeX 言語的には \char`\\ 等とする方がわかりやすいかもしれません. ↩︎