![Почему вложение некоторых команд xstring приводит к ошибкам?](https://rvso.com/image/405343/%D0%9F%D0%BE%D1%87%D0%B5%D0%BC%D1%83%20%D0%B2%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5%20%D0%BD%D0%B5%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D1%85%20%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%20xstring%20%D0%BF%D1%80%D0%B8%D0%B2%D0%BE%D0%B4%D0%B8%D1%82%20%D0%BA%20%D0%BE%D1%88%D0%B8%D0%B1%D0%BA%D0%B0%D0%BC%3F.png)
Почему объединение некоторых командпакет 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}