マクロツイーター

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

今年も思い切りTeXでAdvent Calendarする件について

思い切り!!


TeX & LaTeX Advent Calendar 2023

TeXLaTeX Advent Calendar 2023

とっておきのTeXLaTeXネタを皆で持ち寄って楽しむ
TeX & LaTeX Advent Calendar」
今年は 12回目 の開催となります。
皆さんの、心をこめた素敵なネタを例によってお待ちしております!
ハッシュタグは「 #texadvent2023 」
TeXLaTeX初心者大歓迎。 ←重要
TeXLaTeX非初心者大歓迎。

今年の重点テーマはコレです!

今年の重点テーマ

今年の重点テーマはコレです。
「(La)TeXで幸せになる方法」

TeXLaTeXの大きな特徴は 「とにかく拡張性が高い」 ということです。これは他の競合技術(SATySFi、Typstなど)と比較して顕著な点であり、LaTeXのレベルでは「他よりも圧倒的に豊富な量の拡張ライブラリを有する」、またTeXプログラミング(LuaTeXのLuaも含む)のレベルでは「(もはや無法といえるほどに)自由に機能拡張する手段が与えられている」という特徴をもちます。このため(La)TeXは「使いこなせばこなすほど文書の可能性が広がって、どんどん 幸せ になる」ソフトウェアということができるでしょう。

(La)TeXを使いこなす方法を広く伝授して、人類をもっと幸せにしていきましょう!

例によって「重点テーマ」は「制限」ではありません。

(前略)……以下のいずれかテーマに該当する何かを書きます。

  • 「(La)TeXで幸せになる方法」に大いに関連するTeXLaTeXネタ。
  • 「(La)TeXで幸せになる方法」にチョット関連するTeXLaTeXネタ。
  • 「(La)TeXで幸せになる方法」にサッパリ関連しないTeXLaTeXネタ。

このように、以前と同じく、TeXに関連するもの(\expandafter ベンチプレスとか、\futurelet スクワットとか、\afterassignment デッドリフトとか、……)なら何でも構いません。

皆さんの、心温まるTeXネタで寒い冬を乗り越えましょう☃️!

もっともっと画期的なTypst用文書テンプレートをつくった件

今日11月11日は、きりたんぽの日!

というわけで、1TeXのコンセプトを踏襲した上でさらに画期的、さらに本質的に進化させた、Typst用の新しい文書テンプレートである「sc1Typst」をつくりました!😃

そして偶然ですが1、まさに今日の日に某ツイッタァー(現𝕏)において「本質的なConf」であるナントカConfが3年ぶりに開催されました2

さっそく、sc1Typstについて発表しました3😃

発表スライド(抜粋)

発表の時に使ったスライド4の全体については、すぐ上の某ツイッタァー(現𝕏)のカード内のリンクからたどれる某ツイッタァー(現𝕏)のスレッドを見てください。

まとめ

というわけで、⛄芸人の皆さんはぜひ、Typstしましょう!💁


  1. ……ということにしておきましょう🙃
  2. 聞くところによると、ところ変わって帯広ではアレなConfであるTeXConfが開催されていたらしい。
  3. ……ということにしておきましょう🙃🙃
  4. ……ということにしておきましょう🙃🙃🙃

記号と数字だけで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のように^の個数を増やした形になります。

イマドキのmacOSで平和に“pLaTeXでヒラギノ”する話(※ただし画期的)

ここ数日、異常な暑さが続いています。いや、もはやこの「異常な暑さ」が正常なのかもしれません。考えてみれば、他にも「異常な物価高」など、「異常」が常態化して……(中略)……ゆきだるま☃!

というわけで、今年も正常に「ゆきだるま☃の日」がやってきました!

某氏🙃がざんねん🙃な話

……といいたいところですが、某氏🙃については残念ながら今年は異常なことになってしまいました。少し体調が思わしくない状況が続いていて、事前に構想していた大ネタが完成できませんでした。

何か小ネタで代わりになるものはないかと、「X」(旧ツイッタァー)1を眺めていると……。

よし、コレに決めました(奥村先生、ありがとうございました🙇(えっ))

というわけでpLaTeXで“Macヒラギノ”を使う」について考察してみます。

Macヒラギノ”の難しさを語る(つもりだった)話

最近のMac者なら「LaTeXで“Macヒラギノ”を使うのは極めて難しいので、素人は手を出すな」という話を聞いたことがあるでしょう。「“Macヒラギノ”でLaTeX」が困難である理由はTeX関連のソフトウェアの事情が深く関わっていて……(略2

LuaLaTeXなら簡単に“Macヒラギノ”できる話

実は、イマドキの日本語LaTeXの世界では“Macヒラギノ”を使う極めて簡単な方法があります。それはLuaLaTeX(+LuaTeX-ja)を使うことです。例えば、luatexja-fontspecを利用して次のように3書くと標準の明朝体を「ヒラギノ明朝ProN W3」に設定できます。

% LuaLaTeX文書
\documentclass{ltjsarticle}
\usepackage{luatexja-fontspec}
\setmainjfont{Hiragino Mincho ProN W3}

ここで注目すべきなのは「Hiragino Mincho ProN W3」というフォント名(英語名ですが4)を指定していることです。LuaLaTeXも「OSのフォント管理」とは全く独立に動いているという点では従来の(p)LaTeXと同じです。しかしLuaTeXでは自前の(Luaによる)実装により「フォント名からOSにインストール済のフォントファイルを見つける」という処理を実現しています。このため、LuaLaTeXでは「macOSのバージョンによるフォントファイルの構成の差異」の影響を受けることなく、OSに「Hiragino Mincho ProN W3」(という英語名のフォント)がある限りはその名前を指定して利用できるわけです。

やっぱりLuaLaTeXはスゴイですね🙂

チョット補足してみる

「LuaTeX-jaで“Macヒラギノ”」を実用したいという場合は、luatexja-presetパッケージが便利です。次のようにパッケージを読むだけで“Macヒラギノ”の明朝2ウェイト・ゴシック3ウェイト・丸ゴシック1ウェイトが標準の和文フォントに設定されます5

% LuaLaTeX文書のプリアンブルで
\usepackage[hiragino-pron,deluxe]{luatexja-preset}% ProN系を使う場合
%\usepackage[hiragino-pro,deluxe]{luatexja-preset}% Pro系を使う場合

deluxeは多ウェイト設定を有効にするためのオプションです(japanese-otfパッケージと同様)。

なお、jlreqクラスを利用する場合は注意が必要(参考)で、このときはluatexja-presetパッケージのオプションリストに

jfm_yoko=jlreq,jfm_tate=jlreqv

を追加する必要があります。

% LuaLaTeX文書
\documentclass[tate,book,paper=a6,fontsize=9pt]{jlreq}
\usepackage[hiragino-pron,deluxe,jfm_yoko=jlreq,jfm_tate=jlreqv]{luatexja-preset}

でもやっぱりpLaTeXで“Macヒラギノ”したい話

話を戻しましょう。LuaLaTeXはスゴイわけですが、今でも日本ではpLaTeXが広く使われています。先にあげた奥村氏のアンケート結果を見る限りは「pLaTeXで“Macヒラギノ”を使う」という課題は大いに考える価値があるでしょう。もちろん、「macOSをアップデートしたら何も動かなくなって詰んだ」というリスクを抱え続けるのも全く望ましくありません。「pLaTeXで“Macヒラギノ”を平和に使い続ける方法」が求められているわけです。

一見して極めて困難な問題です。しかしこれがLaTeXの困難な問題」の一つと判断できているのであれば、自ずと解決方針も見えてきます……そうです。

出力を☃に変えればよい。

今回もこの方針に従って画期的な解決方法を考えてみましょう。出力を☃に変えるといっても、そもそも目的が「ヒラギノフォントの文字を出力する」ことなので、いつものように「scsnowmanの赤マフラーの☃を出力して終わり(めでたしめでたし😊)」というわけにはいきません。あの“無表情な☃”pLaTeXで出力する必要があります。

結局「“Macヒラギノ”の文字をpLaTeXで扱う必要がある」ので全く問題が簡単になっていないようにも見えますが、大きな進展もあります。これまではヒラギノの2万グリフを全て使おうとしていたところを、本質的に必要な1つのグリフ(CID+8218)だけに絞ることに成功しました。1つの文字だけであればフォント自体を扱う必要はありません。そう、画像化すればよいわけです!

画期的な解決策のアイデア

先述の通り、LuaLaTeXでは“Macヒラギノ”を簡単に取り扱えるので、LuaLaTeXでstandaloneパッケージを使うなどの方法で「“Macヒラギノ”の☃」の「PDF形式の画像」を作り出すことができます。

% LuaLaTeX文書; UTF-8
\documentclass{standalone}
\usepackage{fontspec}
\setmainfont{Hiragino Mincho ProN W3}
\begin{document}% 中身は☃だけ
\end{document}

pLaTeX+dvipdfmxでは「PDF形式の画像」を貼り込めるので、あとは“まるで直接文字を書いたように見えるように適切に調整”してこの☃の画像を貼ればいいわけです。PDFの中にPDFを貼った形なので外の文字と全く同じように「フォントの字」が配置されている状態になるため、検索・コピーペーストも問題なく行えます。

pLaTeXで本質的に“Macヒラギノ”できる話

このアイデアに基づいて、実際にLaTeXパッケージをつくってみました

以下の2つのファイルを使います。

  • genschira.sh : ☃のPDF画像を生成するためのbashスクリプト
  • schira.sty: ☃のPDF画像を貼り込むためのLaTeXパッケージ。

まずは、macOSのコマンドシェルで、genschira.shを何も引数を付けずに実行します。

genshira.sh

すると、XeLaTeXが実行されて「“Macヒラギノ”の☃」のPDF画像ファイル“schira-k.pdf”が生成されます。

本質的な“Macヒラギノ”(もどき🙃)の画像

※あいにく自分はWindows者でヒラギノは持っていないので、この記事ではscsnowmanでつくった「ヒラギノもどき」の無表情な☃の画像を代わりに使います。賢明な読者の皆さんは「本当はヒラギノの無表情な☃である」と思い込んでください(えっ😲)

※先の説明ではLuaLaTeXを使いましたが、実は今の用途だとLuaLaTeXよりもXeLaTeXの方がより“安全”である6ため、genschira.shではXeLaTeXを使っています。

schiraパッケージは次の命令を提供します。

  • \schira: genschira.shで生成した☃のPDF画像を“まるで直接☃の字を書いた”ように適切に配置する。

※schiraパッケージはpLaTeX+dvipdfmxに限らず、全ての「PDF画像を扱えるワークフロー」をサポートします。ドライバオプションはグローバルオプションに指定してください。

% pLaTeX+dvipdfmx
\documentclass[dvipdfmx,a4paper]{jsarticle}
\usepackage{schira}
\begin{document}
吾輩は{\schira}である。
意味はまだない。
\end{document}

出力結果

もちろん、schiraパッケージは縦組みの文書もサポートしています。次に挙げるのはjlreqクラスを利用した縦組みの文書の例です。

% pLaTeX+dvipdfmx
\documentclass[tate,dvipdfmx]{jlreq}
\usepackage{schira}
\begin{document}
吾輩は{\schira}である。

意味はまだない。
\end{document}

出力結果

もちろん、☃以外の文字はdvipdfmxの既定設定のまま(上掲の画像では原ノ味フォント)なのでヒラギノではないのですが、そもそも☃以外の文字は全く本質的ではないため、結果として「pLaTeX文書が本質的にヒラギノになった」といって問題ないでしょう。

今回も「出力を☃に変える」という画期的なアイデアにより見事にLaTeXの困難な問題を解決することができました。やっぱり☃はスゴイ!😃

まとめ

ヒラギノの無表情な☃も非ヒラギノの無表情な☃も、どっちも素敵😊


  1. 最近のニュース記事だとこの書き方が多いようです😉
  2. 本当は書く予定でしたが時間切れのため省略(ざんねん🙃)
  3. この例はあくまで説明のためのものなので、初級者はマネをしないでください。
  4. LuaTeX+luaotfloadではフォント名は英語名のみが認識されるようです。
  5. . "kanji-config-updmapで標準和文フォントをヒラギノに設定して、(u)pLaTeX+japanese-otf(deluxe付)を使った場合と同じです。「ヒラギノ明朝W2」があればそれも利用できます。"
  6. TeX関連のソフトウェアとしては極めて例外的なのですが、macOSのXeTeXは「macOSのフォント管理」を通してフォント名の解決処理を行います。だから「macOSヒラギノが使える限りはLaTeXでも使える状態が維持されてほしい」という目的に鑑みるとXeLaTeXを使うのが最適ということになります。

dvipdfmxの色スタックがアレなのをなんとかする(ナントカもする)

アレForumのアレな話

dvipdfmxがアレらしい。

Each \color command executes

\special {color push \current@color }\aftergroup \reset@color

but the push is never followed by a pop (except at the end of the job).

The color stack apparently has a limitation of 127 or 128 positions (you get red, I get blue, so it can be off by one depending on the version of the software).

ただし、このTeX Forumの問題のように「トップレベルで\colorを大量に使うと失敗する」ことについては割と簡単に対処できそうである。

トップレベルではそもそも\aftergroupで挿入したトークンは実行されないので、\reset@colorは元々一度も実行されていないはずである。だから色スタックに関するトップレベルでの整合性は元々要求されていないことになる。となると、次の動作をすればよい。

  • まず最初に初期色をスタックに積んでおく。*1
  • トップレベルで\set@colorが実行された場合は本来の動作の代わりに「色スタックをpop → \current@colorをpush」をする(トップレベルなので\aftergroupはそもそも無意味)。これでスタックの深さは変わらなくなる。

イマドキのTeXエンジンであればe-TeX拡張の\currentgrouplevelが使えるので「いまトップレベルにいるか」が判定できる。

やってみた

というわけで、なんとかしてみた。

あとは適当な例で試すだけだが、折角なんとかしたのだからナントカすることにする。

% upLaTeX + dvipdfmx (essential)
\documentclass[dvipdfmx]{jsarticle}
\usepackage{xcolor}
\colorlet{R}{red}\colorlet{B}{blue}\colorlet{G}{green!50!black}
\usepackage{bxdpx-tchack}
\newcommand*\cS[1]{\color{#1}\color{black}}
\newcommand*\cNice[7]{%
  \cS{#1}\cS{#2}\cS{#3}\cS{#4}\cS{#5}っ \cS{#6}っっ♪\cS{#7}っっ♪}
\newcommand*\cNicePar{%
  \cNice{R}{B}{R}{G}{B}{R}{R} \cNice{B}{B}{G}{R}{G}{B}{B}\par
  \cNice{G}{R}{R}{R}{B}{G}{G} \cNice{R}{G}{R}{B}{G}{R}{R}\par}
\begin{document}
\cNicePar \cNicePar \cNicePar \cNicePar \cNicePar
\end{document}

出力(トッテモ素敵😊)

まとめ

色とりどりのナントカはトッテモ素敵😊😊😊

*1:これはcolorパッケージ自体が既に行っているようではあるが、ここでの内部動作は“\color{black}”を(トップレベルの)プリアンブルで実行したのと全く同じなので、これが想定外の状態を引き起こすことはないはずである。

例のマークシートのアレを実際にzrefでやってみた話

というわけで、実際にやってみた。

問題の整理

元ネタ。

某マクロツイーターのzref関連の解説記事。

実装

変更部分のコードのみを示す。

%%↓★以下を追加
\RequirePackage{zref}
\zref@newprop{countermark}[1]{0}
\zref@newlist{marksheet}
\zref@addprop{marksheet}{countermark}

%%↓\markboxletter の実装を修正
\newcommand{\markboxletter}[2][]{%
  \stepcounter{countermark}%
  \ifx{#1%
    }{}{}%
  \else
    \ExpandArgs{nx}\zref@setcurrent{countermark}{\thecountermark}%★変更
    \zref@labelbylist{#1}{marksheet}%★変更
  \fi
  \katakana{countermark}%
  \setcounter{itermark}{1}%
  \whiledo{\value{itermark}<#2}{%
    \stepcounter{countermark}%
    \katakana{countermark}%
    \addtocounter{itermark}{1}%
  }%
}

%%↓\refmarkboxletter の実装を修正
\newcommand{\refmarkboxletter}[2][]{%
  \setcounter{tempcountermark}{\zref@extract{#1}{countermark}}%★変更
  \setcounter{itermark}{0}%
  \whiledo{\value{itermark}<#2}{%
    \katakana{tempcountermark}%
    \stepcounter{tempcountermark}%
    \addtocounter{itermark}{1}%
  }%
}

変更内容は以下の通り。

  • “★”の箇所の追加・修正。
  • LaTeXカーネルの相互参照機能は使わないので\refstepcounterを全部\stepcounterに変更した。

zrefする場合の問題点

この実装の中で、特にTeX言語初級者にとって一番難しいと思われるのは次の箇所である。

    \ExpandArgs{nx}\zref@setcurrent{countermark}{\thecountermark}%★変更

ここでは「LaTeXのcountermarkカウンタ」の現在の値を「zrefのcountermarkプロパティ」に設定しようとしている。ところが、zrefのプロパティは「トークン列を格納する」ものであるため、カウンタの現在の値(を表すトークン列)を得ようとすると、何らかの展開制御が必要になってしまう。具体的には次のようなコードを実行する必要がある。

\zref@setcurrent{countermark}{\thecountermark の完全展開】}

TeX言語の展開制御に慣れている人であれば、次のような「踏み台パターン」を用いたコードを書くのは容易であろう。

\edef\next{%
  \noexpand\zref@setcurrent{countermark}{\thecountermark}}
\next

しかし、所望の展開パターンからこのコードへ到達する過程は直観的ではなく、TeX言語初級者にとって大変な困難を伴うものであることは間違いない。zrefは別に「初級開発者向け」のパッケージではないので仕方がないことではあるが、もう少しどうにかならないものだろうか。

そこでここでは「\ExpandArgs を使う」という方法を採用してみた。\ExpandArgsは2022-06-01版のカーネルで追加された命令で「expl3の直観的な展開制御をTeX言語のコードで使えるようにする」ためのものである。今の場合は次のように考える。

  • 以下の\zref@setcurrentの呼出の引数について、展開制御をしたい。
    \zref@setcurrent{countermark}{\thecountermark}
  • 第1引数のcountermarkはそのままにしたい → n指定
  • 第2引数の\thecountermarkは完全展開したい → x指定
  • 従って、\ExpandArgs{nx}\zref@setcurrentの前に置けばよい。

その結果が本節の冒頭に示したコードになる。

    \ExpandArgs{nx}\zref@setcurrent{countermark}{\thecountermark}%★変更

まとめ

  • やっぱりzrefパッケージは便利
  • 初級者が展開制御したい場合は\ExpandArgsが便利かもしれない

チョットTypstしてみた話

Typstって何

Typstは今年(2023年)の3月頃に一般公開された、新しい組版エンジンです(現在はベータ版)。

詳細については以下の記事を参照しましょう。

zenn.dev

開発も活発に続けられていて、5月20日リリースの0.4.0版では、なんと、日本語組版のサポートが始まりました😲 今も着実に改良が加えられているようです。

というわけで、早速Typstでチョット文書を作ってみました。

Typstでナベアツする件

プログラマブル組版ソフトウェアで何か文書を作るとなれば、最初にやるべきなのはやっぱりNabeAzzですね。元ネタはもう忘れ去られていると思うので、改めて問題の内容を説明しておきます。

「NabeAzz問題」は以下の版面出力を行うプログラムを実装する問題です。

  • 与えられた正整数 n に対して、1から n までの整数の十進表記を順に空白区切りで出力する。
  • ただし、整数が「3の倍数である」または「その十進表記に数字3を含む」場合は、“アホなフォント”に切り替えて出力する。

「フォントを変えて出力する」という要件があるので組版用プログラム言語専用の問題といえます。これまでTeXPostScriptMetaPostでの実装が知られています。

やってみた

#import "zrsimple.typ"

#show: zrsimple.doc.with(
  paper: "a5",
  title: "NabeAzz with Typst",
  author: "ZR"
)

// "アホなフォント"のファミリ名
#let aho-font = "Allura"
// nabeazz(n integer) -> content
// 入力がnのときの"NabeAzz問題"の出力.
#let nabeazz(lmt) = {
  range(1, lmt+1).map(n => {
    if calc.rem(n, 3) == 0 or "3" in str(n) {
      text(size: 2em, font: aho-font, str(n))
    } else {
      str(n)
    }
  }).join([ ])
}

#nabeazz(40)

Typstでドドスコする件

TypstでNabeAzzができたとなると、当然の帰結として次はドドスコをやりたくなりますね🙃

「ドドスコ問題」は次のようなプログラムを実装する問題です。

この問題には組版的要件が含まれないため、イロイロな言語での実装が行われています。組版用言語に限ると、TeXSATySFiでの実装があります。

やってみた

#import "zrjasimple.typ"

#show: zrjasimple.doc.with(
  title: "Typst でドドスコしてみた",
  author: "某 ZR"
)

// ddsk(seed integer) -> string
// 乱数種をseedとしたときの"ドドスコ問題"の出力の文字列.
#let ddsk(seed) = {
  let (m, a) = (0x7FFFFFFF, 16807)
  let next(v) = calc.rem(v * a, m)
  let r = next(next(seed))
  let s = 0
  while s != 0x888 {
    let b = calc.odd(int(r / 0x4000))
    s = calc.rem(s * 2 + int(b), 0x1000)
    if b {"ドド"} else {"スコ"}
    r = next(r)
  }
  "ラブ注入♡"
}

#ddsk(80000)

まとめ

現在のところ、TeXやSATySFiと比べるとTypstには以下のような大きなメリットがあります。

というわけで、皆さんも、Typstでイロイロやってみましょう!💁