\documentclass{article}
\usepackage{xifthen, xstring}
\newcommand{\IfOne}[3]{
\if\TokenIsIn#1
#2
\else
#3
\fi
}
\newcommand{\IfTwo}[3]{
\ifthenelse{\equal{\TokenIsIn}{#1}}{#2}{#3}
}
\newcommand{\IfThree}[3]{
\IfBeginWith{\TokenIsIn}{#1}{#2}{#3}
}
\newcommand{\TokenIsIn}{}
\newcommand{\settok}[1]{\global\let\TokenIsIn=#1}
\settok{a}
\begin{document}
\IfOne{a}{Yes}{No}\\
\IfTwo{a}{Yes}{No}\\
\IfThree{a}{Yes}{No}
\end{document}
输出
Yes
No
No
为什么\IfTwo
和会\IfThree
返回No
?
答案1
有了\let\TokenIsIn=a
,控制序列\TokenIsIn
就变成了不可扩展的标记;更准确地说,它变成了“隐式的a
”。
测试\if\TokenIsIn a
并\ifx\TokenIsIn a
返回 true,但\ifthenelse
以不同的方式进行比较;基本上,\ifthenelse{\equal{X}{Y}}
执行以下操作
\edef\first{X}\edef\second{Y}\ifx\first\second
X
当 且\TokenIsIn
时Y
,此测试返回 false a
,因为\first
和\second
没有相同的第一级扩展:隐式标记与标记不同。
对于情况来说,\IfBeginWith
情况稍微复杂一些,但本质上测试失败,因为类似的操作\edef\first{\TokenIsIn}
也会执行,并且\edef
在\TokenIsIn
不是改变成a
。
\ifthen
仅具有\IfBeginWith
明确的应该使用令牌。
如果您执行以下三个测试,则返回 true
\newcommand{\settok}[1]{\gdef\TokenIsIn{#1}}
答案2
从另一个角度来看,该stringstrings
包非常慢,主要用于正则表达式。但如果你的问题属于这种风格,那么它有一些有用的例程:
\documentclass{article}
\usepackage{stringstrings}
\begin{document}
\def\mystring{dcbadcbadcba}
\findchars{\mystring}{a} a's found in string
Position \whereischar{\mystring}{a} is where the first `a' is found
\testmatchingchar{\mystring}{3}{a}
Character 3 \ifmatchingchar is \else is not \fi an `a'.
\testmatchingchar{\mystring}{4}{a}
Character 4 \ifmatchingchar is \else is not \fi an `a'.
\end{document}
\whereischar
我发现宏产生了一些杂散空格
答案3
\IfBeginWith
使用此代码(显示\meaning\IfBeginWith
)
\long macro:->\@ifstar {\let \@xs@assign \@xs@expand@and@detokenize
\@xs@IfBeginWith@@ }{\let \@xs@assign \@xs@expand@and@assign \@xs@IfBeginWith@@
即,它对输入代码进行扩展和去标记化\TokenIsIn
,但是\if
... 会一直进行扩展直到找到不可扩展的标记,这就是 的情况(至少我认为如此)\global\let\...=#1
,它不可扩展并且不能评估为true
(或此处为“否”)。
但是,使用\newtoks
寄存器并在其中扩展(或更好:使其可扩展)它\TokenIsIn
并\the\MyToken
不能阻止\if...
扩展构造。
参见字母 b 的示例输出,它应该No
适用于所有宏。
\documentclass{article}
\usepackage{xifthen, xstring}
\newcommand{\IfOne}[3]{%
\if\TokenIsIn#1
#2%
\else
#3%
\fi
}
\newcommand{\IfTwo}[3]{%
\ifthenelse{\equal{\TokenIsIn}{#1}}{#2}{#3}%
}
\newcommand{\IfThree}[3]{%
\IfBeginWith{\TokenIsIn}{#1}{#2}{#3}%
}
\newcommand{\TokenIsIn}{\the\MyToken}
\newtoks\MyToken
\newcommand{\settok}[1]{\MyToken={#1}}%
\settok{a}
\begin{document}
\IfOne{a}{Yes}{No}
\IfTwo{a}{Yes}{No}
\IfThree{a}{Yes}{No}
\IfOne{b}{Yes}{No}
\IfTwo{b}{Yes}{No}
\IfThree{b}{Yes}{No}
\end{document}