為什麼嵌套一些 xstring 指令會導致錯誤?

為什麼嵌套一些 xstring 指令會導致錯誤?

為什麼要組合一些指令xstring包導致錯誤?例如,當我編譯以下 MWE 時:

\documentclass{article}
\usepackage{xstring}
\begin{document}
\section{A}
    \StrCompare{\StrChar{bbbb}{4}}{\StrChar{aaaa}{3}}% are 4th character of first argument with 3th character of second argument differ ---> result 1 (yes and in first position)
\end{document}

它回傳錯誤:

! Undefined control sequence.
\xs_StrChar__ ...ef \xs_arg_ii {#2}\edef \xs_call 
                                                  {\noexpand \xs_testopt {\n...
l.5 ...mpare{\StrChar{bbbb}{4}}{\StrChar{aaaa}{3}}
                                                  % are 4th character of fir...

?

答案1

這是一個相當常見的問題,xstring因為(大多數)它的命令在僅擴展上下文中不起作用(在\edefor\expanded或 or \write... 內),因此每個命令必須在下一個命令開始之前完全執行。簡而言之,它們不能嵌套。顯示相同問題的一個更簡單的範例是定義:

\newcommand\ifequal[2]{%
  \def\tempa{#1}%
  \def\tempb{#2}
  \ifx\tempa\tempb
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi}

然後使用以下命令\edef

\edef\test{\ifequal{abc}{abc}{true}{false}}

這會拋出錯誤:

! Undefined control sequence.
\ifequal #1#2->\def \tempa 
                           {#1}\def \tempb {#2} \ifx \tempa \tempb \expandaf...
l.13 \edef\test{\ifequal{abc}{abc}
                                  {true}{false}}
?

但是,如果您在室外使用它,它\edef就會起作用。

為了允許在另一個命令中使用一個命令的結果xstring,大多數命令都有一個最終可選參數,它是一個用於儲存處理結果的宏,然後您需要單獨執行每個步驟並收集每個步驟的結果:

\documentclass{article}
\usepackage{xstring}
\begin{document}
\section{A}
\StrChar{bbbb}{4}[\tempA]
\StrChar{aaaa}{3}[\tempB]
\StrCompare{\tempA}{\tempB}
\end{document}

希望很快我就能完成我的可擴展版本xstring;-)

答案2

您不能\StrChar在 的參數中使用\StrCompare

這裡有兩種實作:一種使用xparseexpl3,一種使用xstring.請注意,前者是完全可擴展的,後者則不能。

\documentclass{article}
\usepackage{xparse}
\usepackage{xstring} % for comparison

\ExplSyntaxOn

\NewExpandableDocumentCommand{\comparestringitems}{mmmmmm}
 {
  % #1 = first string
  % #2 = item number
  % #3 = second string
  % #4 = item number
  % #5 = true text
  % #6 = false text
  \str_if_eq:eeTF { \str_item:nn { #1 } { #2 } } { \str_item:nn { #3 } { #4 } } { #5 } { #6 }
 }

\prg_generate_conditional_variant:Nnn \str_if_eq:nn { ee } { TF,T,F,p }

\ExplSyntaxOff

\newcommand{\comparestringitemsxstring}[6]{%
  \StrChar{#1}{#2}[\compareA]%
  \StrChar{#3}{#4}[\compareB]%
  \StrCompare{\compareA}{\compareB}[\compareC]
  \ifnum\compareC=0 #5\else#6\fi
}

\begin{document}

\comparestringitems{aaaa}{4}{bbbb}{3}{true}{false}

\comparestringitems{aaaa}{4}{bbab}{3}{true}{false}

\comparestringitemsxstring{aaaa}{4}{bbbb}{3}{true}{false}

\comparestringitemsxstring{aaaa}{4}{bbab}{3}{true}{false}

\edef\test{\comparestringitems{aaaa}{4}{bbab}{3}{true}{false}}
\texttt{\meaning\test}

\end{document}

在此輸入影像描述

透過簡單的修改,您也可以將巨集傳遞給\comparestringitems

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewExpandableDocumentCommand{\comparestringitems}{mmmmmm}
 {
  % #1 = first string
  % #2 = item number
  % #3 = second string
  % #4 = item number
  % #5 = true text
  % #6 = false text
  \str_if_eq:eeTF { \str_item:en { #1 } { #2 } } { \str_item:en { #3 } { #4 } } { #5 } { #6 }
 }

\prg_generate_conditional_variant:Nnn \str_if_eq:nn { ee } { TF,T,F,p }
\cs_generate_variant:Nn \str_item:nn { e }

\ExplSyntaxOff

\newcommand{\strA}{aaaa}
\newcommand{\strB}{bbbb}
\newcommand{\strC}{bbab}

\begin{document}

\comparestringitems{\strA}{4}{\strB}{3}{true}{false}

\comparestringitems{\strA}{4}{\strC}{3}{true}{false}

\edef\test{\comparestringitems{\strA}{4}{\strC}{3}{true}{false}}
\texttt{\meaning\test}

\end{document}

在此輸入影像描述

相關內容