------------
\documentclass[uplatex,dvipdfmx]{jlreq}
\usepackage[T1]{fontenc}
\usepackage{tikz}
\def\項目A{3.6}\def\項目B{2.3}\def\項目C{1.2}
% 実際は不規則な値が10個くらい続く
\begin{document}
\begin{tikzpicture}
\node[right] at (1, \項目A) {愛の行方};
\node[left] at (4, \項目A) {10};
\node[right] at (1, \項目B) {柿の味わい};
\node[left] at (4, \項目B) {7};
\node[right] at (1, \項目C) {指し方教室};
\node[left] at (4, \項目C) {3};
\end{tikzpicture}
% 実際は5×10くらいの表みたいな感じ
\end{document}
------------
ここで、同じようなものがつづくので、マクロにできないかと考え、次のようにしました。
------------
\documentclass[uplatex,dvipdfmx]{jlreq}
\usepackage[T1]{fontenc}
\usepackage{tikz}
\newcounter{項目カウンタ}
\setcounter{項目カウンタ}{0}
\def\項目A{3.6}\def\項目B{2.3}\def\項目C{1.2}
\def\項目行#1#2{%
\stepcounter{項目カウンタ}
\node[right] at (1, \項目\Alph{項目カウンタ}) {#1};
\node[left] at (4, \項目\Alph{項目カウンタ}) {#2};
}
\begin{document}
\begin{tikzpicture}
\項目行{愛の行方}{10}
\項目行{柿の味わい}{7}
\項目行{指し方教室}{3}
\end{tikzpicture}
\end{document}
------------
しかし、エラーになります。\expandafter や \csname\endcsname あるいは \edef や \@Alph\c@項目カウンタ を使えばいいかなと思い、いろいろ試しましたがだめでした。どうすれば前者と同じ結果が出せるでしょうか。
最初、自分でも「\項目\Alph{項目カウンタ} のうち、\項目 がそのままで、\Alph{項目カウンタ} が A や B に変わらないといけないから、このままじゃだめだろう」と思っていました。だから、頭に \expandafter を置いてみましたがだめでした。
いろいろネットなどで調べて、\csname が使えそうかなと思いました。しかし、そのコマンドは使ったことがなく、よくわからないまま
\項目\csname\Alph{項目カウンタ}\endcsname
としてしまったので、うまくいきませんでした。
おかげさまで、\csname の使い方がなんとなく分かりました。ありがとうございました。
いえいえ、わかりにくいだなんて。ご親切にありがとうございます。
私は \csname を使ったことがなかったので、本当にこの命令でいいのか確証がなく、別の命令をつかうのかもしれないと思い、よく読まなかったからでした。
これって私の感想ですけど、むしろ、マクロを組む上で、よくあるパターンが紹介されてあればいいなと思います。
たとえば、\hoge[#1]<#2>{#3}{#4}を定義するとき、[#1]が省略されていれば空文字、<#2>が省略されていれば<fuga>を指定したのと同じとするならば、
\def\hoge{\@ifnextchar[%
{直後が[のときの処理、そして、\@hoge}{直後が[でないときの処理、そして、\@hoge[]}
}
\def\@hoge[#1]{\@ifnextchar<%
{直後が<のときの処理、そして、\@@hoge[#1]}{直後が<でないときの処理、そして、\@@hoge[#1]<fuga>}
}
\def\@@hoge[#1]<#2>#3#4{%
#1#2#3#4
}
のようにする、などです。この場合、よく事前に
\newif\ifxxx\xxxfalse
と、一旦偽とし、\@ifnextchar のなかで \xxxtrue のように真に変えるパターンも多いかと思います。
マクロ一個一個の意味も大事ですが、よくある使い方が充実していればいいなと思いました。
素晴らしい解決方法が提示されているので、気が引けるのですが 別解を考えてみました。
今回提示されている方法は、項目と文字を紐づけていますが、 多数あるのであれば、インデックス番号でアクセスできる 配列操作をした方が良いのでは ... と考えていて検討していました。
参考URL https://tex.stackexchange.com/questions/283934/changing-color-in-foreach-using-arrayjob
上記 URL では以下の様な方法について話題にしてています。
- \def\項目{{ 3.6, 2.3, 1.2 }} % newcommand でも可
- arrayjob /arrayjobx を使って
- \newarray\項目\readarray{項目}{ 3.6 & 2.3 & 1.2 }
- expl3 と xparse を利用して配列宣言できる definearrayマクロ利用
- \definearray{項目XX}{ 3.6, 2.3, 1.2 }
なお、真ん中の arrayjob /arrayjobx は array を書き換えているので非推奨とのことでしたのと 内部的に \if 関連の処理がうまくいかないので検討は中断しました。
参考になれば幸いです。
よくこんな例をを見つけましたね。私も普段は Tikz を使わないのですが、今回は Tikz をつかうので、foreach が使えないかなと思いました。しかし、座標は指定できても、表示させる項目をいわば配列変数にしないとならないので断念しました。TeX で配列変数は困難と思っていましたので、意外でした。\pgfmathsetmacro というのも初めて知りました。それにしても、この方法は便利ですね。さっそくこの方法を取り入れてみようと思います(2つめの例は expl3 を使っているのでさっぱりわかりませんでしたが)。
本当に今回はためになりました。\csname の使い方を覚え、配列変数のようなやり方も覚えられました。質問して本当によかったです。ありがとうございました。
foreach も検討されたのなら 無名で 多次元配列 感覚で
- インデックス番号の初期化は zero オリジンか否か
- stepupcounter がうざい
- 本来ならインデックスの最大値チェックは必要
- foreach ならインデックス番号も取得はできるが ...
- foreach ならループ毎に幾つかの値を取得できる ...
ということでデータをくっつけて、表の様に管理できるようにしてみました
\begin{tikzpicture} \foreach \y / \a / \b in { 3.6 / 愛の行方 / 10, 2.3 / 柿の味わい / 7, 1.2 / 指し方教室 / 3, } { \node[right] at (1, \y) {\a}; \node[left ] at (4, \y) {\b}; } \end{tikzpicture}
つぶやき
tikz に限らず、最近のマニュアルは 100 ページ 200 ページ超えのものが多いので、 texdoxc tikz などで pdf ブラウジングでは探しにくいですね。
なので、他のスレッドでも何度かぶつぶつ呟いていますが、コマンドラインで探します。
上記 foreach は以下のようにして検索してます。
rga -C 3 'foreach' $pgfmanual
rga は ripgrep 関連の ripgrep-all で pdf なども文字列検索可能です。
$pgfmanual は、何度も検索する場合、コマンドラインの編集を簡単にするため変数に入れています。
bash / zsh なら
pgfmanual=/usr/local/texlive/2022/texmf-dist/doc/generic/pgf/pgfmanual.pdf
クロスプラットフォームなシェルインタフェース nu(nushell) なら
let pgfmanual = '/usr/local/texlive/2022/texmf-dist/doc/generic/pgf/pgfmanual.pdf'
の様にして設定可能です。
pdf マニュアルのパスは 「texdoc -l tikz」で表示されるものから選択してください
rga でよく併用するオプション例
- 「-i」 ignore case
- 「-e」 複数条件検索の場合「-e 検索ア -e 検索B」の様に列挙
- 「-A 数値」 after 由来で、検索した行以下 n 行
- 「-B 数値」 こちらは before 由来なので「前 n 行」
- 「-C 数値」 これは center 由来なので「前後 n 行」
grep ならテキストファイルになら使えましたが、pdf には使えませんでした。ま、目次や索引、あるいは Acrobat Reader の検索機能でいいかなと思いました(とはいえ、ためしに foreach を検索すると 1300 以上も見つかり、読む気が失せましたが)。
さて、いろいろ調べていくうちに、先日教えていただいた \pgfmathparse は配列に限らず、一般に計算結果を与え、結果は \pgfmathresult に保存されることが分かりました。実は、QA に挙げた例では必要最小限の例で y 座標が不規則と書きましたが、実際は「ほぼ等差数列」で、一部、等差になっていなかったのです。うまい方法が思いつかず、10 個くらいだからと、\項目A 、\項目B 、としましたが、\pgfmathparse や座標同士の計算などを覚え、そんな面倒なことをしなくても、うまく式で表現できるようになりました。結局、せっかく教えていただいた \csname や、 \pgfmathparse による配列は使わなくなってしまいました。でも、きっと将来、別の場面で活用する機会があるでしょう。
今回の質問は、学ぶことが多くありました。本当にありがとうございました。