如何执行可扩展字符串比较?

如何执行可扩展字符串比较?

我需要执行字符串比较(字符串相等)。如果宏不可扩展(例如包含\def\let),则会在使用它的地方引起问题。

我尝试使用\ifthenelse同名的包,但它似乎无法扩展(\def出现与我在宏中使用时相同的问题)。

\ifthenelse{\equal{a}{b}}{if-case}{else-case}

如何#1以可扩展的方式测试两个字符串(以及一个常量)是否相等?

答案1

您可以使用expl3\strcompare宏只是可扩展内部 功能\str_if_eq:nnTF.

\documentclass{article}
\usepackage{expl3}

\ExplSyntaxOn
\cs_new_eq:NN \strcompare \str_if_eq:nnTF
\ExplSyntaxOff

\begin{document}

start\par
\strcompare{abc}{def}{OOPS}{OK}\par
\strcompare{abc}{abcd}{OOPS}{OK}\par
\strcompare{abcd}{abc}{OOPS}{OK}\par
\strcompare{a}{}{OOPS}{OK}\par
\strcompare{}{a}{OOPS}{OK}\par
end

\medskip

start\par
\strcompare{abc}{abc}{OK}{OOPS}\par
\strcompare{}{}{OK}{OOPS}\par
end

\end{document}

在此处输入图片描述

答案2

我已经读过\usepackage{pdftexcmds},您可以使用\pdf@strcmp,但尚未检查它在这种情况下是否有效。

或者,下面的代码定义了\expandable@if@equal{str1}{str2}{if-case}{else-case}。如@JavierBezos注释中所述,不考虑空格(所以"a b"= "ab"),而考虑到空格的版本将更难实现(如果可能的话?)。它可以按如下方式使用:

\makeatletter
start%
\expandable@if@equal{abc}{def}{OOPS}{OK}%
\expandable@if@equal{abc}{abcd}{OOPS}{OK}%
\expandable@if@equal{abcd}{abc}{OOPS}{OK}%
\expandable@if@equal{a}{}{OOPS}{OK}%
\expandable@if@equal{}{a}{OOPS}{OK}%
end

start%
\expandable@if@equal{abc}{abc}{OK}{OOPS}%
\expandable@if@equal{}{}{OK}{OOPS}%
end
\makeatother

打印内容(请注意,没有插入多余的空格):

startOKOKOKOKOKend
startOKOKend

定义如下\expandable@if@equal

\makeatletter

%         #1       #2          #3    #4                                  \sepend
% Params: {if-case}{else-case} \sepr \sepr                               \sepend
% Or:     {if-case}{else-case} B     right-…(may be *nothing*)\sepr\sepr \sepend
\def\@expandable@if@equal@empty#1#2#3#4\sepend{%
  \ifx#3\sepr% #3right… = Empty string, a.k.a. "\sepr"
    % First case in the signature above (#3=\sepr, #4=sepr)
    #1% The strings are both empty, and therefore equal. Execute #1.
  \else%
    % Second case in the signature above (#3=one char, #4=right…\sepr\sepr)
    #2% The right string is longer (there's at least one more character), so they are different. Execute #2.
  \fi%
}%
%         #1       #2         #3          #4       \sepl #5    #6                        \sepr #7        \sepend
% Params: {if-case}{else-case}{left-first}{left-…} \sepl \sepr *nothing*                 \sepr *nothing* \sepend
% Or:     {if-case}{else-case}{left-first}{left-…} \sepl B     right-…(may be *nothing*) \sepr \sepr     \sepend
\def\@expandable@if@equal@somechar#1#2#3#4\sepl#5#6\sepr#7\sepend{%
  \ifx#5\sepr% #5#6 = Empty string, a.k.a. "\sepr"
    % First case in the signature above (#5=\sepr, #6=*nothing*, #7=*nothing*)
    #2% But the left string was not empty, so we run else-case
  \else%
    % Second case in the signature above (#5=one char, #6=right…, #7=\sepr)
    \ifx#3#5% First character of left == first character of right
      \@expandable@if@equal{#1}{#2}#4\sepl\sepl#6\sepr\sepr\sepend% Recursion on the rest
    \else%
      #2% The strings are different at this character, execute #2.
    \fi%
  \fi%
}%
% Two possibilities:
%               #1       #2          #3    #4                       \sepl #5          \sepend
% \@expandable@if@equal {if-case}{else-case} \sepl *nothing*                \sepl <rest>      \sepend
% \@expandable@if@equal {if-case}{else-case} A     left-…(may be *nothing*) \sepl \sepl<rest> \sepend
\def\@expandable@if@equal#1#2#3#4\sepl#5\sepend{%
  \ifx#3\sepl% #3#4 = Empty string, a.k.a. "\sepl"
    % First case in the signature above (#3=\sepl, #4=*nothing*, #5=<rest>)
    \@expandable@if@equal@empty{#1}{#2}#5\sepend%
  \else%
    % First case in the signature above (#3=one char, #4=left…, #5=\sepl<rest>)
    \@expandable@if@equal@somechar{#1}{#2}{#3}{#4}#5\sepend%
  \fi%
}
\def\expandable@if@equal#1#2#3#4{%
  % \@expandable@if@equal#1\sepl#4%#2\sepl#4
  %
  % \@expandable@if@equal{#4}\sepl\sepl%
  \@expandable@if@equal{#3}{#4}#1\sepl\sepl#2\sepr\sepr\sepend%
}%

\makeatother

相关内容