我知道三个宏可以测试两个完全展开的字符串是否相等:
\ifthenelse{\equal{<op1>}{<op2>}}{<true>}{<false>}
(ifthen
包裹)\IfStrEq{<op1>}{<op2>}{<true>}{<false>}
(xstring
包裹)\ifstr{<op1>}{<op2>}{<true>}{<false>}
(scrbase
包裹)
有趣的是,它们有一个共同的缺点:它们很脆弱,这意味着
- 我们必须
\protect
在移动论证中对它们进行阐述(例如在的论证中\section
)。 - 它们在 PDF 字符串扩展(例如 PDF 轮廓)的上下文中无法正常工作,正如
hyperref
包裹。
最小示例:
\documentclass{article}
\usepackage{xstring}
\usepackage{hyperref}
\newcommand*{\juhu}{%
juhu%
}
\newcommand*{\test}[1]{%
\IfStrEq{#1}{juhu}{Juhu!}{Oje!}%
}
\begin{document}
\tableofcontents
\section{\test{\juhu}}
%% \section{\protect\test{\juhu}}
\end{document}
因此我的问题是:是否有可能实现一个完全扩展其操作数但消除上面列出的限制的相等性测试?
答案1
\documentclass{article}
\usepackage{pdftexcmds}
\usepackage{hyperref}
\newcommand*{\juhu}{juhu}
\newcommand*{\nojuhu}{nojuhu}
\makeatletter
\newcommand*{\test}[1]{%
\ifnum\pdf@strcmp{#1}{juhu}=\z@ Juhu!\else Oje!\fi
}
\makeatother
\begin{document}
\tableofcontents
\section{\test{\juhu}}
\section{\test{\nojuhu}}
\end{document}
使用\pdf@strcmp
frompdftexcmds
是为了允许使用 XeLaTeX 和 LuaLaTeX 进行测试。pdflatex
使用 就足够了\pdfstrcmp
。
\pdf@strcmp{A}{B}
如果在完全扩展为不可扩展标记之后,字符串相等,则返回 0;如果按字典顺序(基于最终去标记列表的 ASCII 码)A
在前面,则返回 -1;如果在后面,则返回 1 。B
A
B
(当然,需要 e-TeX,所以不需要 Knuth TeX。)
答案2
这没有那些限制,但也有其他限制。买家要小心:-)
\documentclass{article}
\usepackage{hyperref}
\newcommand*{\juhu}{%
juhu%
}
\makeatletter
\def\test#1{%
\expandafter\xtest\romannumeral`\Q#1\muskipdef\valign juhu\muskipdef\voffset{yes}{no}%
}
\def\xtest#1#2#3#4#5{\xxtest}
\def\xxtest#1#2\valign#3#4\voffset{%
\ifx\muskipdef#1%
\ifx\muskipdef#3%
\expandafter\expandafter\expandafter\@firstoftwo
\else
\expandafter\expandafter\expandafter\@secondoftwo
\fi
\else
\ifx\muskipdef#3%
\expandafter\expandafter\expandafter\@secondoftwo
\else
\xiterate{#2}{#4}%
\fi
\fi}
\def\xiterate#1#2\fi\fi{\fi\fi\expandafter\xtest\romannumeral`\Q#1\valign#2\voffset}
\typeout{[[\test{\juhu}]]}
\typeout{[[\test{x\juhu}]]}
\typeout{[[\test{\juhu\empty}]]}
\begin{document}
\tableofcontents
\section{\test{\juhu}}
\end{document}
答案3
这里有一个宏,它逐个字符地比较两个字符串,并且完全可扩展,因此很强大。它非常适合您的测试用例。请注意,如果输入不只包含字符串,它可能会失败。例如,包含的竞争会导致很多问题。
这个\romannumeral-`0
技巧是将输入完全展开,至少展开到第一个字符。然后分离这个字符,并以相同的方式展开和拆分第二个输入。比较两者,如果相等,则重复整个过程,直到找到两个不同的字符或到达两个字符串的末尾。
\documentclass{article}
\usepackage{hyperref}
\newcommand*{\juhu}{%
juhu%
}
\makeatletter
\newcommand\ifstreq[2]{%
\expandafter\@ifstreq\romannumeral-`0#1\relax\@nnil\romannumeral-`0#2\relax\@nnil
}
\def\@ifstreq#1#2\@nnil#3\@nnil{%
\expandafter\@@ifstreq#3\@nnil{#1}{#2}
}
\long\def\@afterfi#1#2\fi{\fi#1}%
\def\@@ifstreq#1#2\@nnil#3#4{%
\ifcase0%
\ifx\relax#1\empty
\ifx\relax#3\empty 2\else 1\fi
\else
\if#3#1\else 1\fi\fi
\space
\@afterfi{%
\expandafter\@ifstreq\romannumeral-`0#4\@nnil\romannumeral-`0#2\@nnil}%
\or
\expandafter\@secondoftwo
\else
\expandafter\@firstoftwo
\fi
}
\makeatother
\newcommand*{\test}[1]{%
\ifstreq{#1}{juhu}{Juhu!}{Oje!}%
}
\begin{document}
\tableofcontents
\section{\test{\juhu}}
\end{document}
答案4
这里是另一个完全可扩展的宏,它逐个字符地比较两个字符串。但是,这里\csname
用于完全扩展字符串和确保两者具有相同的 catcode。如果您将字符串与内部值(例如\jobname
字符不是正式字母)进行比较,这一点很重要。
请注意,如果任何输入不能完全扩展为字符,则此方法将导致错误。这还排除了许多(并非所有)非英语字母(如德语变音符号)的使用,这些字母是以宏形式实现的。
\documentclass{article}
\usepackage{hyperref}
\newcommand*{\juhu}{%
juhu%
}
\makeatletter
\newcommand\ifstreq[2]{%
\expandafter\expandafter\expandafter
\@ifstreq\expandafter\string\csname#1\expandafter
\expandafter\expandafter\endcsname
\expandafter\expandafter\expandafter\relax
\expandafter\expandafter\expandafter\@nnil
\expandafter\string\csname#2\endcsname\relax\@nnil
}
\long\def\@afterfi#1#2\fi{\fi#1}
\def\@ifstreq#1#2\@nnil#3#4\@nnil{%
\ifcase0%
\ifx\relax#1\empty
\ifx\relax#3\empty 2\else 1\fi
\else
\if#3#1\else 1\fi\fi
\space
\@afterfi{\@ifstreq#2\@nnil#4\@nnil}%
\or
\expandafter\@secondoftwo
\else
\expandafter\@firstoftwo
\fi
}
\makeatother
\newcommand*{\test}[1]{%
\ifstreq{#1}{juhu}{Juhu!}{Oje!}%
}
\begin{document}
\tableofcontents
\section{\test{\juhu}}
\end{document}