
Я делаю концертные программы для своих студенческих выступлений, используя класс ConcProg. В песнях много повторений, поэтому я хотел бы создать стенографию.
Так что вместо этого
\begin{composition}{Folk Song}{}{Twinkle Twinkle Little Star}{Student Name}
\end{composition}
Что-то вроде этого.
\newcommand{\twinkle}{{Folk Song}{}{Twinkle Twinkle Little Star}}
\newcommand{\studentname}{{Student Name}}
\begin{composition}\twinkle\studentname
\end{composition}
Однако, \newcommand, похоже, любит только несколько наборов скобок, когда они используются для аргументов для этой конкретной новой команды. Насколько я могу судить, он игнорирует отдельные скобки {т. е. скобки, не связанные с аргументами для этой конкретной \newcommand или команд, размещенных внутри \newcommand}. В случае этой пользовательской среды он выдает ошибку.
Ниже приведен еще один пример (не использующий пользовательскую среду).
%standard input
\newcommand{\wbalTwo}[2] {
This is the Wikibook about LaTeX
supported by #1 and #2}
\item \wbalTwo{John Doe}{Anthea Smith}
%trying to use new command to input args. In this instance, it seems to ignore the internal braces and treats both internally-braced items as a single text string.
\newcommand{\wbalTwo}[2] {
This is the Wikibook about LaTeX
supported by #1 and #2}
\newcommand{\passargs}
Так есть ли простой способ добиться того, чтобы они имели одинаковый результат?
решение1
Из того, что вы нам рассказали до сих пор, следует, что воспроизвести проблему невозможно, и поэтому отслеживание/выявление источника проблемы в некоторой степени связано с догадками.
Сначала несколько общих замечаний — надеюсь, мои догадки верны и мои замечания окажутся полезными:
- Во время сбора аргументов для макросов или сред из потока токенов расширениенетсработало.
- В случае его наличия (La)TeX удалит самый внешний уровень фигурных скобок, которые окружаютвесьаргумент при вставке этого аргумента в текст замены во время расширения.
После «выкапывания» класса ConcProg на CTAN (https://ctan.org/pkg/concprog), я обнаружил, что среда composition
обрабатывает четыре аргумента:
- ⟨автор⟩
- ⟨годы рождения (и смерти)⟩
- ⟨название композиции⟩
- ⟨необязательное описание⟩
Таким образом с
\begin{composition}{Folk Song}{}{Twinkle Twinkle Little Star}{Student Name}
⟨whatsoever environment-body⟩
\end{composition}
- первый аргумент -environment
composition
будет:Folk Song
, - второй аргумент -environment
composition
будет пустым, - третий аргумент -окружения
composition
будет:Twinkle Twinkle Little Star
, - четвертый аргумент -окружения
composition
будет:Student Name
,
в то время как с
\begin{composition}\twinkle\studentname
\end{composition}
- первый аргумент -environment
composition
будет:\twinkle
, - второй аргумент -окружения
composition
будет\studentname
, - третий аргумент -окружения
composition
будет:\end
, - четвертым аргументом -environment
composition
будет:composition
.
Это потому, что расширениенетсрабатывает, когда LaTeX собирает аргументы для макросов или сред.
В зависимости от того, как вставляются аргументы, когда LaTeX выполняет/раскрывает макросы, лежащие в основе composition
среды, такой способ извлечения аргументов может привести к разного рода странному/ошибочному/проблемному поведению.
Я могу предложить настроенный вариант -environment composition
, называемый mycomposition
, который отвечает за расширение:
На самом деле среда вообще не обрабатывает никаких аргументов. Вместо этого она проверяет, является ли следующий токен в ее теле среды расширяемым или нет. Если это так, расширение будет происходить до тех пор, пока не будет найден нерасширяемый токен. (Помните, что фигурные открывающиеся скобки {
не являются расширяемыми токенами. ;-)) Затем она захватит аргумент. Она делает это четыре раза для захвата 4 аргументов. Затем внутренне она передает эти четыре аргумента макросу, лежащему в основе -environment composition
:
\documentclass{ConcProg}
\makeatletter
\newcommand\UD@CheckWhetherNextExpandable[2]{%
\def\UD@reserved@a{#1}%
\def\UD@reserved@b{#2}%
\UD@@CheckWhetherNextExpandable
}%
\newcommand\UD@@CheckWhetherNextExpandable{%
\futurelet\UD@reserved@c\UD@@@CheckWhetherNextExpandable
}%
\newcommand\UD@@@CheckWhetherNextExpandable{%
\ifx\UD@reserved@c\@sptoken\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\afterassignment\UD@@CheckWhetherNextExpandable\let\UD@reserved@c= }%
{%
\expandafter\ifx\noexpand\UD@reserved@c\UD@reserved@c
\expandafter\UD@reserved@b
\else
\expandafter\UD@reserved@a
\fi
}%
}%
\newcommand\UD@ExpandUntilFirstUnexpandableAndAddToUD@reserved@d[1]{%
\ifx\relax#1\relax\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\expandafter\endgroup\UD@reserved@d}%
{\UD@CheckWhetherNextExpandable
{\expandafter\UD@@CheckWhetherNextExpandable}%
{\expandafter\UD@AddNextTo\expandafter{\@gobble#1}\UD@reserved@d}%
}%
}%
\newcommand\UD@AddNextTo[3]{%
% \edef..\the\toks@-route prevents halving of hashes.
\toks@\expandafter{#2{#3}}%
\edef#2{\the\toks@}%
\UD@ExpandUntilFirstUnexpandableAndAddToUD@reserved@d{#1}%
}%
\newcommand\UD@ExpandAndAccumulateKArgsAndPassTo[2]{%
\begingroup
\def\UD@reserved@d{#2}%
\expandafter\UD@ExpandUntilFirstUnexpandableAndAddToUD@reserved@d
\expandafter{\romannumeral\number\number#1 000}%
}%
\newenvironment{mycomposition}%
{\UD@ExpandAndAccumulateKArgsAndPassTo{4}{\composition}}%
{\endcomposition}%
\makeatother
\newcommand{\twinkle}{{Folk Song}{}{Twinkle Twinkle Little Star}}
\newcommand{\studentname}{{Student Name}}
\begin{document}
\begin{composition}{Folk Song}{}{Twinkle Twinkle Little Star}{Student Name}%
environment body
\end{composition}
\begin{mycomposition} \twinkle\studentname
environment body
\end{mycomposition}
\begin{mycomposition} \twinkle {Student Name}
environment body
\end{mycomposition}
\begin{mycomposition} {Folk Song}{}{Twinkle Twinkle Little Star} \studentname
environment body
\end{mycomposition}
\begin{mycomposition}{Folk Song}{}{Twinkle Twinkle Little Star}{Student Name}
environment body
\end{mycomposition}
\end{document}