
У меня следующая ситуация с вложенным циклом:
\begingroup
\def\do##1{%
\begingroup
\def\do####1{%
\csletcs{somemacro@##1@####1}{someothermacro@##1@####1}}%
\dolistloop\somelista
\endgroup}%
\dolistloop\somelistb
\endgroup
где мне нужно, чтобы \csletcs
определение существовало вне двух групп, нонетглобально. Есть хороший трюк от Мартина Шаррера в комментарии к этому вопросу:
Как извлечь ценность из группы?
но это не работает в цикле, как этот, так как размещение \endgroup
s во внутреннем цикле действительно портит следующие итерации цикла. Есть ли способ (etoolbox подходит) вытащить определения \csletcs
из групп, не прерывая дальнейшие итерации циклов? Я предполагаю, что мне нужны группы, иначе аргументы цикла do не будут ссылаться должным образом.
Для полноты картины приведем попытку решения с использованием трюка Мартина Шаррера:
\begingroup
\def\do##1{%
\begingroup
\def\do####1{%
\edef\@z{\endgroup\endgroup\csletcs{somemacro@##1@####1}{someothermacro@##1@####1}}\@z}%
\dolistloop\somelista
\endgroup}%
\dolistloop\somelistb
\endgroup
Это работает для первой вложенной итерации, и результирующий cs определяется правильно вне групп. К сожалению, затем группы закрываются, и следующие итерации — это настоящий беспорядок.
решение1
Ваш пример немного неполный (мне пришлось внести некоторые изменения, чтобы скомпилировать его), но суть ответа заключается в том, чтобы просто собрать ваши определения в список токенов (задать глобально), а затем расширить список после второй группы (вызвав локальные определения).
\documentclass{article}
\usepackage{etoolbox}
\begin{document}
\makeatletter
\def\somelista{x}
\def\somelistb{y}
\texttt{\meaning\somemacro@y@x}
\def\someothermacro@y@x{a}
\begingroup
\def\do#1{%
\begingroup
\def\do##1{%
\global\toks1=\expandafter{\the\toks1 \csletcs{somemacro@#1@##1}{someothermacro@#1@##1}}}%
\dolistloop\somelista
\endgroup}%
\dolistloop\somelistb
\endgroup
\the\toks1
\texttt{\meaning\somemacro@y@x}
\makeatother
\end{document}
Выдает: «неопределенный макрос:->a» в качестве набранного вывода.
решение2
Вы можете использовать любой обработчик для обработки списка, используя \forlistloop
вместо \dolistloop
; поэтому вам не нужно переопределять \do
группу, чтобы не затирать определение внешнего цикла: просто используйте два разных обработчика.
\documentclass{article}
\usepackage{etoolbox}
\newcommand\processlistb[1]{%
\def\temp{#1}%
\forlistloop\processlista\somelista
}
\newcommand\processlista[1]{%
\csletcs{somemacro@\temp @#1}{someothermacro@\temp @#1}%
\csshow{somemacro@\temp @#1}%
}
\listadd\somelista{a}
\listadd\somelista{b}
\listadd\somelista{c}
\listadd\somelistb{x}
\listadd\somelistb{y}
% Just to add some mock definitions
\csdef{someothermacro@x@a}{xa}
\csdef{someothermacro@x@b}{xb}
\csdef{someothermacro@x@c}{xc}
\csdef{someothermacro@y@a}{ya}
\csdef{someothermacro@y@b}{yb}
\csdef{someothermacro@y@c}{yc}
% Do the iterations
\forlistloop\processlistb\somelistb
\stop
Соответствующая часть файла журнала:
> \somemacro@x@a=macro:
->xa.
<recently read> \somemacro@x@a
l.29 \forlistloop\processlistb\somelistb
?
> \somemacro@x@b=macro:
->xb.
<recently read> \somemacro@x@b
l.29 \forlistloop\processlistb\somelistb
?
> \somemacro@x@c=macro:
->xc.
<recently read> \somemacro@x@c
l.29 \forlistloop\processlistb\somelistb
?
> \somemacro@y@a=macro:
->ya.
<recently read> \somemacro@y@a
l.29 \forlistloop\processlistb\somelistb
?
> \somemacro@y@b=macro:
->yb.
<recently read> \somemacro@y@b
l.29 \forlistloop\processlistb\somelistb
?
> \somemacro@y@c=macro:
->yc.
<recently read> \somemacro@y@c
l.29 \forlistloop\processlistb\somelistb
?