ifthen
パッケージによる文字列一致判定
LaTeXマクロで「文字列一致判定」による場合分けを行いたい場合,ifthen
パッケージの \equal
を使うのが簡単です。ifthen
パッケージは次の記事に詳しく解説されています。
例えば,#1
に与えられた文字列が ほげ
であるか否か(完全一致)によって \TRUE
,\FALSE
のいずれかを実行するマクロ \hogecheck
は次のように定義できます。
\documentclass{jlreq} \usepackage{ifthen} \def\TRUE{一致しました!☃} \def\FALSE{一致しません☂} \newcommand\hogecheck[1]{\ifthenelse{\equal{#1}{ほげ}}{\TRUE}{\FALSE}} \begin{document} \hogecheck{ほげ}% => 一致判定 \hogecheck{}% => 不一致判定 \hogecheck{☃☃☃}% => 不一致判定 \hogecheck{ほげほげ}% => 不一致判定 \hogecheck{☃ほげ}% => 不一致判定 \hogecheck{ほげ☃}% => 不一致判定 \hogecheck{☃ほげほげ☃}% => 不一致判定 \hogecheck{☃ほげ☃ほげ☃}% => 不一致判定 \end{document}
問題点
ですが,\ifthenelse
を使うと完全展開可能性が要求される文脈下で使えないという問題があります。
% \edef の中身に使えない \edef\result{\hogecheck{ほげ}} % => コンパイルエラー % \csname ~ \endcsname による動的な制御綴生成に使えない \csname\hogecheck{ほげ}\endcsname % => コンパイルエラー % \input によるファイル名に使えない \input{\hogecheck{ほげ}.tex} % => コンパイルエラー
\def
のパターンマッチによる解決策
こういうときは,\def
によるパターンマッチを活用して文字列探索を行うというのが常套手段となります。
\def\TRUE{YES} \def\FALSE{NO} \makeatletter \def\hogecheck#1{% \@hogecheck#1ほげ\relax } \def\@hogecheck#1ほげ#2\relax{% \ifnum0\if"#1"1\fi\if"#2"\else1\fi=11 \@@hogecheck#1#2\relax \else \FALSE \fi } \def\@@hogecheck#1ほげ#2\relax{% \ifnum0\if"#1"1\fi\if"#2"1\fi=11 \TRUE \else \FALSE \fi } \makeatother
\hogecheck
はダミーの ほげ
を含めて引数を \@hogecheck
に投げます。次に \@hogecheck
は,「#1
が空かつ#2
が空でない」という条件の可否を調べることで,元の \hogecheck
の引数内に ほげ
が含まれているか否かを判定します。そして,それが成立する場合には,ダミーの「ほげ
」を除いた部分を \@@hogecheck
に投げ,\@@hogecheck
は「ほげ
」の前後に余計なトークンが含まれていないかどうかを調べることで,引数が「ほげ
」と完全一致するか否かを判定する,という仕組みになります。
\if
系トークンによる空文字列判定,およびAND条件の表現には,以前の記事で紹介したテクを活用しました。
\def
のパターンマッチによる文字列探索は,去年の記事でも用いました。
さて,これで完全展開可能な文字列一致判定ができましたので,このように定義した \hogecheck
を用いて,次のような処理が可能となります。
\def\TRUE{YES} \def\FALSE{NO} \edef\result{\hogecheck{ほげ}} % => \result は macro:->YES で定義される \edef\result{\hogecheck{ふが}} % => \result は macro:->NO で定義される \csname\hogecheck{ほげ}\endcsname % => \YES になる \csname\hogecheck{ふが}\endcsname % => \NO になる \input{\hogecheck{ほげ}.tex} % => YES.tex がロードされる \input{\hogecheck{ふが}.tex} % => NO.tex がロードされる
飛び道具:expl3 による解決策
実は,このような古風でトリッキーな解決策を組み立てなくとも,expl3 が LaTeX カーネルに組み込まれている現代ならば,飛び道具として expl3 の \str_if_eq:nnTF
(これは e-TeX の追加プリミティブである \pdfstrcmp
を使って実装されています)を使うことで,問題は一気に解決します。これが今風の解決策でありましょう。
\def\TRUE{YES} \def\FALSE{NO} \ExplSyntaxOn \cs_new_eq:NN \CompareStringsTF \str_if_eq:nnTF \ExplSyntaxOff \edef\result{\CompareStringsTF{ほげ}{ほげ}{\TRUE}{\FALSE}} % => \result は macro:->YES で定義される \edef\result{\CompareStringsTF{ふが}{ほげ}{\TRUE}{\FALSE}} % => \result は macro:->NO で定義される \csname\CompareStringsTF{ほげ}{ほげ}{\TRUE}{\FALSE}\endcsname % => \YES になる \csname\CompareStringsTF{ふが}{ほげ}{\TRUE}{\FALSE}\endcsname % => \NO になる \input{\CompareStringsTF{ほげ}{ほげ}{\TRUE}{\FALSE}.tex} % => YES.tex がロードされる \input{\CompareStringsTF{ふが}{ほげ}{\TRUE}{\FALSE}.tex} % => NO.tex がロードされる