引数のパターンマッチング

引数のパターンマッチング

- 前田 やえの の投稿
返信数: 23
いつも大変お世話になっております。早速ですが質問.
小数点の数表示から整数部分のみを取り出したいと思って
以下のマクロを作ったつもり.

\def\章番号#1.#2{#1}

\章番号 5.6
とやると 5が出てきて満足,ところが
 
\章番号 12.34567
とやると
124567
となって3が抜けて4567がくっつく.12 を出したいのです.
このパターンマッチングはどこがいけないのですか?
磯崎秀樹著,LaTeX自由自在,22pageを参考にしています.

前田 やえの への返信

Re: 引数のパターンマッチング

- 帯田 木偶太 の投稿
その定義では、第2引数の終端を示すものがないので、
    \章番号 12.34567
としたときに、“3”という一文字だけが第2引数と認識されます。
そして展開結果が“12”となり、引数として取り込まれなかった“4567”が
続けて出力されます。

解決策はいくつかあると思いますが、次のようなものでいかがでしょうか。

========

\documentclass{jarticle}\relax
\makeatletter
    \def\章番号#1{\章番号@#1\@nil}
    \def\章番号@#1.#2\@nil{#1}
\makeatother
\begin{document}
\章番号{5.6} → 5

\章番号{12.34567} → 12
\end{document}
帯田 木偶太 への返信

Re: 引数のパターンマッチング

- 前田 やえの の投稿
返信ありがとうございます。
今から勉強します.感謝.
とりあえずのみ返信.
前田 やえの への返信

Re: 引数のパターンマッチング

- 帯田 木偶太 の投稿
\tracingmacros という数値パラメーターに正数を代入すると、
マクロ実行時に何が引数として取り込まれたかが
ログ・ファイルに出力されます。
さらに \tracingonline という数値パラメーターに正数を代入すると、
端末画面にも同じ情報が表示されます。
        \def\章番号#1.#2{#1}
        \tracingonline=1\relax
        \tracingmacros=1\relax
        \章番号 12.34567

これでは読みにくいということであれば、マクロの定義を変えて、
次のようにしてタイプセットした結果を見ればよいかもしれません。
        \documentclass{jarticle}\relax
        \def\章番号#1.#2{#1%}
            \\
            第1引数:\quad ``#1''\\
            第2引数:\quad ``#2''\\
        }
        \begin{document}
        \章番号 12.34567
        \end{document}
帯田 木偶太 への返信

Re: 引数のパターンマッチング  コマンド \@nil

- 前田 やえの の投稿
帯田 木偶太さま
すみません,教えてください。
コマンド \@nil の定義は何をしてくれるコマンドですか?
それから
章番号@#1 に出てくる@の意味を知りたいのです.
インターネットサイトとか本でもよいです.

前田 やえの への返信

Re: 引数のパターンマッチング  コマンド \@nil

- 帯田 木偶太 の投稿
》 章番号@#1 に出てくる@の意味を知りたいのです.

@ そのものには特に意味はありません。
“\章番号”から呼び出す下請けマクロを作る必要があったので、
“\章番号”というマクロの下請けとして使うものであるとわかりやすいように
“\章番号@”という名前でマクロを定義したということです。
        ※  \章番号@ でひとかたまりです。
別に“\章番号の下請け”でも“\章番号sub”でもいいわけですが、
“@”を名前の中に含めていれば、ユーザーが不用意に下請けマクロを
呼び出したり再定義したりする心配がなくなるので、下請けマクロの
名前には“@”を入れることが多いです。


》 コマンド \@nil の定義は何をしてくれるコマンドですか?

\@nil は未定義のコントロール・シーケンスです。
未定義ですので、当然、何もしません。
単に、“\章番号@”の引数パターン・マッチングにおける第2引数の終端を
TeX に検知させるために入れた目印です。必ずしも \@nil である必要はなく、
マクロのユーザーが引数の一部と意図して使うことがなさそうなものを
置けばいいので、
        \def\章番号#1{\章番号@#1X}
        \def\章番号@#1.#2X{#1}
と定義しておいて
        \章番号{12.34567} → 12
としても構いません。ただし、この場合、“\章番号”の引数中に
“X”という文字が含まれると、期待どおりに動作しない可能性があります。
未定義で、なおかつ名前に“@”が含まれるコントロール・シーケンスであれば、
マクロのユーザーが引数中に記述する可能性は極めて低いので、
都合がいいわけです。

ちなみに、林 かぐらさんの
        https://okumuralab.org/tex/mod/forum/discuss.php?d=3281&parent=19722
のマクロは、下請けマクロを介さずに、“\章番号”の引数のパターン・マッチングで
第2引数の最後を示す区切り文字列として、空白 1 個を用いたものということに
なります。
帯田 木偶太 への返信

Re: 引数のパターンマッチング

- 前田 やえの の投稿

皆様教えてください。
前回の話を単純化したものです.
\documentclass{jsbook}
%
\begin{document}
\makeatletter
\def\章番号#1{\章番号@#1\@nil}
\def\章番号@#1.#2\@nil{#1}
\makeatother
\章番号{1.1} → 1 \\
%%%
\chapter{C} %第1章
\section{P}
\label{花子}
\ref{花子} → 1.1 \\
%\章番号\ref{花子} %何故ここでエラーstopするのですか?
\expandafter\章番号{\ref{花子}}
%%% ここらあたりでエラー Runaway argument?
% 数値 1 が出るのを期待しています。→ 1
\end{document}
前田 やえの への返信

Re: 引数のパターンマッチング

- 北見 けん の投稿
帯田さんのコメントにある通り、

\tracingmacros=1
\ref{花子} → 1.1 \\
\expandafter\章番号{\ref{花子}} %何故ここでエラーstopするのですか?

のようにしてログファイルを見ると、
エラーに至るまでにマクロがどのように展開されているか確認できます。
原因究明に役立つでしょう。

と、それは今後に役立ててもらうとして、
今回考えられるのは次のようなことです。

\expandafter\章番号{\ref{花子}}

これだと\expandafter がひとつしかないので、
まず \expandafter によって \章番号 の展開が保留されてその次の { (開きブレイス)が「展開」されます。ただし、開きブレイスは展開されても何も変わらないトークンなので、そのままあらためて

\章番号{\ref{花子}}

が実行されることになります。
そうすると \章番号 の引数は「1.1」ではなく「\ref{花子}」ですから \章番号 が想定した形式でないためうまくいきません。

\章番号 が展開されるよりも前に \ref{花子} が展開されるようにするには \expandafter を追加して

\expandafter\章番号\expandafter{\ref{花子}}

とする必要があります。こうすると \章番号 と開きブレイス を保留して先に \ref が展開されます。

ですが、\ref は複雑なマクロなので、一回だけ展開しても 1.1 までにはなってくれませんから、これでもやはりうまくいきません。

\ref{花子}を展開しつくして 1.1 にまでするにはもっと\expandafter を増やしても良いですが、\ref の定義の中身を確認してそれに合わせて \expandafter を塩梅する必要があるのであまり筋が良いとはいえません。
他にもいくつか方法はありますが、例えば次のようにすることもできます。

\edef\temp{\ref{花子}}
\expandafter\章番号\expandafter{\temp}

この \edef というのは \def のようにマクロ定義をする命令ですが、定義の際に \ref{花子} の部分を展開しきってしまって、それによって \temp を定義するというものです。
前田 やえの への返信

Re: 引数のパターンマッチング

- 北見 けん の投稿
帯田さんのコメントにある通り、

\tracingmacros=1
\ref{花子} → 1.1 \\
\expandafter\章番号{\ref{花子}} %何故ここでエラーstopするのですか?

のようにしてログファイルを見ると、
エラーに至るまでにマクロがどのように展開されているか確認できます。
原因究明に役立つでしょう。

と、それは今後に役立ててもらうとして、
今回考えられるのは次のようなことです。

\expandafter\章番号{\ref{花子}}

これだと\expandafter がひとつしかないので、
まず \expandafter によって \章番号 の展開が保留されてその次の { (開きブレイス)が「展開」されます。ただし、開きブレイスは展開されても何も変わらないトークンなので、そのままあらためて

\章番号{\ref{花子}}

が実行されることになります。
そうすると \章番号 の引数は「1.1」ではなく「\ref{花子}」ですから \章番号 が想定した形式でないためうまくいきません。

\章番号 が展開されるよりも前に \ref{花子} が展開されるようにするには \expandafter を追加して

\expandafter\章番号\expandafter{\ref{花子}}

とする必要があります。こうすると \章番号 と開きブレイス を保留して先に \ref が展開されます。

ですが、\ref は複雑なマクロなので、一回だけ展開しても 1.1 までにはなってくれませんから、これでもやはりうまくいきません。

\ref{花子}を展開しつくして 1.1 にまでするにはもっと\expandafter を増やしても良いですが、\ref の定義の中身を確認してそれに合わせて \expandafter を塩梅する必要があるのであまり筋が良いとはいえません。
他にもいくつか方法はありますが、例えば次のようにすることもできます。

\edef\temp{\ref{花子}}
\expandafter\章番号\expandafter{\temp}

この \edef というのは \def のようにマクロ定義をする命令ですが、定義の際に \ref{花子} の部分を展開しきってしまって、それによって \temp を定義するというものです。
北見 けん への返信

Re: 引数のパターンマッチング

- Z. R. の投稿
\edef\temp{\ref{花子}}

ラベル「花子」の参照が未定義の場合は、そもそもこれが実行できないですね。

※この場合、\ref{花子}の動作が「警告を出して太字で??を出力する」であり、明らかに完全展開可能ではない。

Z. R. への返信

Re: 引数のパターンマッチング

- 北見 けん の投稿
ZRさん、ご指摘ありがとうございます。
そうでした。手元で試していませんでした。
\edef だとうまくいかないですね。

## あと、なぜか二重投稿になってしまっていました
## 消していただけると助かります

前田さん、間違ったことを書いてすみませんでした。

未定義の場合の例外処理などいろいろあるので、
内部マクロのお世話になるのが簡単ですね。

\pageref にならって
\def\chapref#1{\expandafter\@setref\csname r@#1\endcsname\@chapref{#1}}
\def\@chapref#1#2{ #1から章番号を切り出す処理。#2は捨てる。 }
とかでしょうか。LaTeXの内部マクロである \@setref が例外処理などを面倒見てくれます。

\@chapref 内の「#1から章番号を切り出す処理」は、具体的には、
他の書き込みで定義されている \章番号 マクロを使って
\def\@cahpref#1#2{\章番号{#1}}
としてもよいですし、下請けマクロの \章番号@ を直接使って
\def\@cahpref#1#2{\章番号@#1.\@nil}
のようにしても良いでしょう。
\def\@cahpref#1#2{\章番号@#1\@nil}
とせずに余分なピリオドをつけておくのは、章番号だけ(節番号がない)の場合のためです。
\章番号 マクロのほうも余分なピリオドを追加して次のようにした方が安全でしょう。
\def\章番号#1{\章番号@#1.\@nil}

(追記です)
上記のように定義したとすると、
\章番号\ref{太郎} や \ref{花子} の代わりに
\chapref{花子} のように使うと章番号が出るようになります。
北見 けん への返信

Re: 引数のパターンマッチング

- 本田 知亮 の投稿
>既に覚えているはずのカウンターの値を返してくれる新しいref
>を作るにはどうすれば良いのですか?

残念ながら,「値」は覚えていても,その値がどのカウンタから得られたものかは記録されていません.

たとえば,

\chapter{AA}%%1章
\section{BB}%%1.1節
\section{CC}%%1.2節
\subsection{DD}%%1.3節
\label{ZZ}

としておきます.

\label{ZZ}で記録されるものはauxを見ると分かる通り,

\newlabel{ZZ}{{1.3}{1}}%%%1はページ番号,ここでは仮の値

であるので,1.3という値のみであり,これが
\thesubsection由来であるとか,1がカウンタchapterの値で,3がカウンタsubsectionの値であるというような情報は一切残っていません.


それで,やりとりをみていると,たぶん,
\ref[chapter]{ZZ}が1,
\ref[subsection]{ZZ}が3,
普通に\ref{ZZ}で1.3,
\pageref{ZZ}で1となるような\refが欲しいということではないでしょうか

そうであると仮定して作ってみると,
ほとんどテストしないですけど,こんな感じでしょうか.
パターンマッチで拾うのではなく,
存在するLaTeXのカウンタそれぞれに対して,
labelを盛大に発行しまくる方針です.

\refは普通の\refとおなじですが
mpfootnoteのせいで,\ref[hoge]{label}で
追加的に参照できるのは
カウンタの値そのものだけです.
\thehogeがi,ii,...になるようなカウンタhogeでも
参照の結果でてくるのは1,2,...です.
#この制限を外そうと思うと,\@eltリストから
#特定の項目を外すとかで
#「緑の本」が欲しくなるので,
#ここまでにしておきます.

\documentclass[tombow,a5j]{jarticle}

\makeatletter

\def\label#1{\@bsphack
\bgroup
\protected@write\@auxout{}{%
\string\newlabel{#1}{{\@currentlabel}{\thepage}%
}%
}%
\def\@elt##1{%
\protected@write\@auxout{}{%
\string\newlabel{#1@##1}{{\the\csname c@##1\endcsname}{\thepage}%
}%
}%
}
\cl@@ckpt
\egroup
\@esphack}

\let\ltx@ref\ref
\let\ltx@page\pageref

\def\ref{\@ifnextchar[%]
{\cnt@ref}{\ltx@ref}
}
\def\cnt@ref[#1]#2{\ltx@ref{#2@#1}}

\def\pageref{\@ifnextchar[%]
{\cnt@pageref}{\ltx@pageref}
}
\def\cnt@pageref[#1]#2{\ltx@pageref{#2@#1}}

\begin{document}
\section{A}\subsection{B}
あああああ
あああああ
あああああ
あああああああ\label{AAA}\ref{AAA}「\ref[section]{AAA}」


\section{A}\subsection{B}\subsubsection{C}
あああああ
あああああ
あああああ
あああああああ\label{ccc}\ref{ccc}「\ref[subsection]{AAA}」



\end{document}
前田 やえの への返信

Re: 引数のパターンマッチング

- 林 かぐら の投稿
\def\章番号#1.#2 {#1}
でどうでしょう。
ただし入力は
\章番号 12.34567(改行)
あるいは
\章番号 12.34567(スペース)~~~
としなければなりませんが。

「パターンマッチング」がテーマなので,このようにしましたが
LaTeX 向きではないかもしれません。
LaTeX としては普通,帯田 木偶太さんの回答のようになるでしょう。
前田 やえの への返信

Re: 引数のパターンマッチング

- 北見 けん の投稿
こんな手もあります。

\def\章番号#1.{#1\begingroup\afterassignment\endgroup\count0=}
とか
\def\章番号#1.{#1\romannumeral-}
とか

どちらもそのまま次のように使えて、

\章番号 5.6
\章番号 12.34567

それぞれ、5と12になると思います。
前田 やえの への返信

Re: 引数のパターンマッチング

- 前田 やえの の投稿
皆様お世話になっております。
\documentclass{jsbook}
%
\begin{document}
\makeatletter
\def\章番号#1{\章番号@#1\@nil}
\def\章番号@#1.#2\@nil{#1}
\makeatother
% → 5 \\
\章番号{12.34567} → 12 \\
\章番号{534.037} → 534
%%%%%%%ここまでは解った,その次なのです%%%%%%
\chapter{C} %第1章
\chapter{A} %第2章
\label{太郎}
\section{P}
\label{花子} %やはり第2章
\chapter{B} %第3章
\label{次郎}
%%%%
\expandafter\章番号\ref{太郎} → 2
%%% ここらあたりでエラー Runaway argument?
\\
\ref{花子} → 2 \\
\ref{次郎} → 3
\end{document}
前田 やえの への返信

Re: 引数のパターンマッチング

- 前田 やえの の投稿
お世話になっております。
この問題は次のような発想から来ています.
\label,\refのことです,
\refしたとき置いてある\labelがどの深さにあってもchapter,section,subsection等の
カウンターの値のみを出力するにはどうすればどうすれば良いのか?
ということでした.
普通は
\chapter{}
 \section{}
 \section{}
 \label{花子}
.....
 \ref{花子}
とやると1.2 が得られますが 1のみを出したい時がありました.
\newcommandを作ってlabel名,カウンター名(例えばchapter)
を任意に与えたとき
既に覚えているはずのカウンターの値を返してくれる新しいref
を作るにはどうすれば良いのですか?

前田 やえの への返信

Re: 引数のパターンマッチング

- 和田 勇 の投稿

この目的でしたら texdoc hyperref で表示される p20 の下部を参考に
\usepackage{hyperref} で \chaptername{花子} でどうでしょうか?

前田 やえの への返信

Re: 引数のパターンマッチング これで解決

- 前田 やえの の投稿
皆様一応当初の目的の疑問が解決出来ましたので報告します.
沢山の方々に教えていただいた結果です,
本当にありがとうございました.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% このプログラムは\labelの位置の深さに関わらず
%章番号のみを出力する.
\documentclass{jsbook}
%これは正しい 2021/12/14
\begin{document}
\makeatletter
% \def\章番号#1{\章番号@#1\@nil}
\def\章番号@#1.#2\@nil{#1}
\def\章番号#1{\章番号@#1.\@nil}
%
\def\chapref#1{\expandafter\@setref\csname r@#1\endcsname\@chapref{#1}}
%\def\@chapref#1#2{ #1から章番号を切り出す処理。#2は捨てる。 }
%\def\@chapref#1#2{\章番号{#1}}
\def\@chapref#1#2{\章番号@#1.\@nil}
\makeatother
%
\章番号{1.1} → 1 \\
%%%
\chapter{C} %第1章
\section{P}
% \label{花子}
\ref{花子} → 2.1 \\
\chapter{Q} %第2章
\section{R}
%
\label{花子}
\chapref{花子}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
ここだよ \chapref{花子}
\end{document}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

前田 やえの への返信

Re: 引数のパターンマッチング これで解決

- 北見 けん の投稿
ご所望の機能が実現できたようで、よかったです。

それはそれとして、
いろいろな方のアドバイスが
なにかマクロ作成についての理解につながったのか気になるので、
その辺りについて簡単にフィードバックをいただけると嬉しく思います。
もしもお時間ありましたら、よろしくお願いいたします。
北見 けん への返信

Re: 引数のパターンマッチング これで解決

- 前田 やえの の投稿
返信遅れて失礼しました.
要するに
\def\章番号@#1.#2\@nil{#1}
\def\章番号#1{\章番号@#1.\@nil}
%
\def\chapref#1{\expandafter\@setref\csname r@#1\endcsname\@chapref{#1}}
\def\@chapref#1#2{\章番号@#1.\@nil}
で良いと思ったのです.
北見 けんさんが教えてくれた\@setref が上手く効いているようです.
他の方のは検証していないです.
ところで
コマンド\@setrefは何をしてくれるコマンドでその定義はどこに書いてあるのですか?

前田 やえの への返信

Re: 引数のパターンマッチング これで解決

- 和田 勇 の投稿
>コマンド\@setrefは何をしてくれるコマンド?

よくわかりませんが ...

>その定義はどこに書いてあるの

「@setref tex」でインターネット検索してみました。

「 https://oversleptabit.com/archives/202 」では「ltxref.dtxの中に定義」をカスタマイズしている例が表示されています。

ですので「kpsewhich ltxref.dtx」などで場所を探して調べてみてはいかがでしょうか。
前田 やえの への返信

Re: 引数のパターンマッチング これで解決

- 北見 けん の投稿
すでに解決済みのところ、お返事いただきありがとうございます。

TeXのマクロについて特に理解が進んだわけではないというのは少し残念ですが。

LaTeX の内部マクロについては、私は latex.ltx を読むようにしています。latex.ltx は ltxref,dtx や ltdefns.dtx のような複数のソースファイルからマクロ定義を抜き出してまとめたもので、latex.exe を実行する際に読み込まれるフォーマットファイルの元となるものです。