マクロツイーター

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

記号と数字だけでTeX言語する話

というわけで、本記事では「TeX言語のコード(LaTeX文書のソースも含む)を記号と数字のみを含む(チョット読みにくい🎄)コードに変換する」ための具体的な手順について解説します。

※対象とするコードはASCII文字のみを含むものに限ります。TeXエンジンの種類には依存しません。

キホン的知識

なんと、インタァーネットには「チョット読みにくいTeX言語のキホン」を解説したスバラシイ記事があります。チョット読みにくいTeX言語初心者はまずこれを読みましょう。

ここで紹介する手順では上記記事の「サーカムフレックスメソッド」(ソース上の文字を代用する^^ab形式の文字コード表記)を利用します。

※本記事では「サーカムフレックスメソッド」のことを(例によって1TeXエスケープ」と呼びます。

英字をグッバイする手順

ASCII文字からなるコードを「記号と数字だけ」にするには英字(A~Z、a~z)を除去する必要があります。このため「英大文字を除去する」「英小文字を除去する」という2つのステップを順に実行することで実現します。

英大文字をグッバイする話

最初のステップとしてASCII文字のコードを「英大文字を含まないもの2」に変換します。これは機械的に処理できず個別に対処する必要がありますが、それほど難しい作業ではありません。元々、TeX言語の「プログラムっぽいコード」では大文字はほとんど使われません。TeXのプリミティブ名やキーワードは全て小文字であり、フォーマットが提供する制御綴名も大部分が小文字のみからなるからです。

このため、英大文字が出現する箇所の多くは「文字を出力する部分」になり、これについては\uppercaseを使うと対処できます。次のようなコードを考えてみましょう。

[example-1.tex](英大文字を含む)
\documentclass{article}
\begin{document}
Hello, ZR world!
\end{document}

\uppercaseを利用することで大文字を消すことができます。

[example-1a.tex](英大文字を除去した)
\documentclass{article}
\begin{document}
\uppercase{h}ello, \uppercase{zr} world!
\end{document}

もちろん、時には大文字を含む名前の制御綴が使われることもあり、これの対処は厄介です。

[example-2.tex](英大文字を含む)
\documentclass{article}
\begin{document}
Hello, {\TeX} world!
\end{document}

この場合は\csname~\endcsname\uppercaseを駆使して対処することになります。

[example-2a.tex](英大文字を除去した)
\documentclass{article}
\begin{document}
\def\smalle{e}
\uppercase{h}ello, \uppercase{\csname t\smalle x\endcsname} world!
\end{document}

少し技巧的なので補足しておきます。\uppercaseは文字トークンだけに作用して制御綴は変化させないので、

\uppercase{\csname t\smalle x\endcsname}
↓実行
\csname T\smalle X\endcsname
↓展開(ここで \smalle も展開)
\TeX

となり結果的に\TeXが実行されます。注意すべきなのは「\uppercaseは展開可能でない」(そして\csname~\endcsnameの中は展開で処理される)ということで、このため\csname\uppercase{t}e\uppercase{x}\endcsnameとは書けません。

もう少し“機械的に処理”したいという場合は「大文字に変換する完全展開可能なマクロ(\upcase)を作成3する」という手法が有効でしょう。

[example-2b.tex](英大文字を除去した)
\documentclass{article}
\makeatletter
\def\upcase#1{\@nameuse{my@uc/#1}}
\def\my@uc@a#1{\uppercase{\my@uc@b#1}}
\def\my@uc@b#1#2{\@namedef{my@uc/#2}{#1}}
\@tfor\my@x:=abcdefghijklmnopqrstuvwxyz\do{%
  \expandafter\my@uc@a\my@x\my@x}
\makeatother
\begin{document}
\upcase{h}ello, {\csname\upcase{t}e\upcase{x}\endcsname} world!
\end{document}

この\upcaseを使うことで変換がかなり楽になります。

英小文字をグッバイする話

[example-3.tex]

先のステップで英大文字を除去したので残っている英字は小文字だけになります。これは「英小文字をTeXエスケープ形式に変換する」ことで機械的に除去できます。英小文字(a~z)のASCIIコードは0x61~7Aであるため、単文字(^^X)のTeXエスケープ形式に直した場合のXの部分の文字コードは0x21~3Aとなり、この範囲の文字は全て記号と数字になるわけです。

変換前: abcdefghijklmnopqrstuvwxyz
変換後: !"#$%&'()*+,-./0123456789:

ただしこの中の「p~y」の範囲については少し注意が必要です。例えば「w3」という文字列の英小文字部分を上記の規則に従ってTeXエスケープに変換すると^^73となりますが、これは16進法のTeXエスケープの形式に合致しているためsという異なる文字列に解釈されてしまいます。

この問題を回避するため、「p~y」の範囲の文字は単文字のTeXエスケープ(^^0~^^7)の代わりに16進法のTeXエスケープ(^^70~^^79)に変換することにします。するとw3の変換結果は^^773となり、別の文字列に解釈されることはなくなります4

まとめると、以下の手順により英小文字を除去できます。

  • まず「p~y」を16進法TeXエスケープ(^^70~^^79)に変換する。
  • 残りの英小文字(a~z)を単文字TeXエスケープ(^^!~^^:)に変換する。

次のような(英大文字を含まない)コードを考えてみましょう。

[example-3.tex](英小文字を含む)
\catcode`\@=11
\newcount\my@n
\my@n=42

先の手順に従って変換すると英小文字を含まないコードが得られます。

[example-3a.tex](英小文字を除去した)
\^^#^^!^^74^^#^^/^^$^^%`\@=11
\^^.^^%^^77^^#^^/^^75^^.^^74\^^-^^79@^^.
\^^-^^79@^^.=42

このexample-3a.texTeXの字句解析の規則の下ではexample-3.texと全く同一のコードと解釈されるわけです。

記号と数字だけで“hello world”をやってみる話

ここまで説明した2つのステップを順に実行することで、どんなTeX言語コードでも「記号と数字だけのコード」に変換できます。例として、“hello world”のLaTeX文書を「記号と数字だけのコード」に変換してみましょう。

[example-4.tex](英字を含む)
\documentclass{article}
\begin{document}
Hello, {\TeX} world!
\end{document}

これは前節で例にあげたexample-2.texと同じものです。従ってここから「英大文字を除去」した結果のコード(の一例)がexample-2a.texとなります。ただし変換後のコードは横に長くなるので、改行を多めに入れておくことにします。

[example-4a.tex](英小文字を含む)
\documentclass{article}
\begin{document}
\def\smalle{e}
\uppercase{h}ello,
\uppercase{\csname
t\smalle x\endcsname}
world!
\end{document}

あとはこのコードを“TeXエスケープ変換”して「英小文字を除去」すれば「数字と記号だけのコード」が完成します。

[example-4b.tex](英字を除去した)
\^^$^^/^^#^^75^^-^^%^^.^^74^^#^^,^^!^^73^^73{^^!^^72^^74^^)^^#^^,^^%}
\^^"^^%^^'^^)^^.{^^$^^/^^#^^75^^-^^%^^.^^74}
\^^$^^%^^&\^^73^^-^^!^^,^^,^^%{^^%}
\^^75^^70^^70^^%^^72^^#^^!^^73^^%{^^(}^^%^^,^^,^^/,
\^^75^^70^^70^^%^^72^^#^^!^^73^^%{\^^#^^73^^.^^!^^-^^%
^^74\^^73^^-^^!^^,^^,^^% ^^78\^^%^^.^^$^^#^^73^^.^^!^^-^^%}
^^77^^/^^72^^,^^$!
\^^%^^.^^${^^$^^/^^#^^75^^-^^%^^.^^74}

まるで解読不能なのでトッテモ素敵😍

実際にLaTeXで処理してみましょう。

example-4bの出力

元のコードと同じ出力が得られました😊

まとめ

というわけで、「TeX言語🤮はカンタンだからツマラナイ🙁」という人はぜひ、使う文字を制限する🎄ことに挑戦してみましょう!💁(えっ)


  1. 筆者が常用している用語が「TeXエスケープ」です。ちなみにこの表記に対する“正式名称”は存在しないようです。(tex.webの中では“expanded characters”のような表現が使われています。)
  2. ただし、「A~I・P~Y」の範囲の文字はTeXエスケープで記号と数字のみの表記(^^41^^49^^51^^59)に変換できるので、実際に問題になるのは「J~O・Z」だけになります。
  3. 「完全展開可能でないもの完全展開可能にする」ための常套手段である「事前に計算してその結果を(擬似)配列に保存する」という手法を使っています。
  4. ^^で始まる16進法のTeXエスケープの16進数値は常に丁度2桁で表されます。Unicode対応のXeTeXやLuaTeXでは0x100以上の文字コードが使われますが、その場合のTeXエスケープ表記は^^^^2603^^^^^^01f986のように^の個数を増やした形になります。