Почему вложение некоторых команд 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поскольку (большинство) его команд не работают в контекстах только для расширения (внутри \edefили \expandedили или \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.

Вот две реализации: одна с xparseи expl3, одна с 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}

введите описание изображения здесь

Связанный контент