
Я просматривал этот ответ и пытался понять код, я супер новичок (мой второй день) в LaTeX и я застрял на следующей части кода, которую я не мог заставить работать в не табличной среде. Вот простейшая форма того, что я не понимаю.
\documentclass{article}
\begin{document}
\newcommand*\f[3]{#1-#2-#3}
\newcommand*\ex[1]{\f#1 - \expandafter\f\@firstofone}
Try \ex{111}{221}
\end{document}
По какой-то причине, которая мне не ясна, в связанном коде последний аргумент не потребляется, а остается для потребления конструкцией expandafter\f\...
. Насколько я понимаю, \expandafter
сначала следует "запустить" \@firstofone
, получить {221}
аргумент, убрать скобки и передать его \f
. Этого не происходит, и я не могу понять, почему.
решение1
Вам нужно использовать, \makeatletter
чтобы это сработало, но это самое меньшее.
Сначала вызов \ex{111}{221}
расширяется до
\f 111 - \expandafter\f\@firstofone{221}
Теперь \f
он развернут и ищет три аргумента, находя 1
, 1
и 1
, поскольку TeX использует один токен, если отсутствует фигурная скобка.
По определению \f
это расширяется и заменяющий текст повторно вставляется во входной поток:
1-1-1 - \expandafter\f\@firstofone{221}
Токены 1-1-1 -
не расширяются, поэтому они отправляются на следующий этап. Теперь остается
\expandafter\f\@firstofone{221}
Это отложит \f
и расширит \@firstofone
, что просто вернет его (аргумент без скобок), поэтому мы получаем
\f221
что становится 2-2-1
. Таким образом, чистый эффект вашего кода заключается в печати
1-1-1 - 2-2-1
что не кажется действительно полезным. Где бы вы его ни нашли, не доверяйте ему.
решение2
Как указал egreg в своем ответе, использование \@firstofone
не очень полезно и не имеет значения в данном конкретном случае. Однако есть случаи, когда этоявляетсяполезно. Для полноты картины я хотел бы привести два примера.
Расширяемые макросы
ВПочему именно эта \expandafter\@firstoftwo
идиома?Приведен типичный пример использования \@firstoftwo
и в полностью расширяемых макросах. , своего рода «функция идентичности» LaTeX, полезна в подобных контекстах, где необходимо обрабатывать только один параметр:\@secondoftwo
\@firstofone
\def\gobbleIfZero#1{%
\ifnum#1=0
\expandafter\@gobble
\else
\expandafter\@firstofone
\fi
}
foo\gobbleIfZero{0}{bar}
foo\gobbleIfZero{123}{bar}
дам
фу
фубар
\@gobble
(как и \@firstofone
) принимает один параметр, но отбрасывает его и расширяет до «ничего».
Исправление кошачьих кодов
Немного сложнее, но и интереснее случай, когда задействованы изменения catcode. Когда TeX анализирует аргументы для макросов, он исправляет catcodes всякий раз, когда считывается текст аргумента. Это не имеет значения в вашем случае, поскольку здесь нет никаких изменений catcodes. Но предположим, что приведен следующий, несколько надуманный пример:
\begingroup
\catcode`4=\active
\gdef 4{four}
\endgroup
\newcommand*\f{\catcode`4=\active}
\newcommand*\exA{\f}
\newcommand*\exB{\expandafter\f\@firstofone}
{\exA{345}--{345}}
{\exB{345}--{345}}
Это приводит к
3четыре5-3четыре5
345-3четыре5
Первые четыре строки определяют глобальный макрос, 4
который расширяется до four
. Обычно4
имеет код 12 (другой), поэтому мы меняем его на 13 (активный), чтобы иметь возможность сделать из него макрос. \f
здесь возвращает этот макрос в область действия при выполнении.
При \exA
выполнении код кота 4
изменяется на 13, что впоследствии делает4
его расширенным four
в обеих следующих двух группах. Здесь вообще нет параметров, так что это просто.
С другой стороны, в\exB
{345}
макросе обрабатывается первая часть \@firstofone
, которая просто возвращает тот же текст,но исправляет котокодиз4
до 12. После исправления его больше нельзя изменить! Даже если изменение кода кота \f
обработанодопервый 345
, это не окажет на него никакого влияния. Поскольку catcodes второго {345}
еще не были исправлены, изменения все равно будут применяться к этой группе.
Такое поведение весьма удобно, если вы хотите внедрить дополнительный код в существующие макросы, которые обрабатывают изменения catcode, например:\verb
(вдохновленоэта жемчужина TeX):
\begingroup
\catcode`\/\active
\catcode`\_\active
\@firstofone{%
\verb|%
\catcode`\/\active \def/{\par}%
\catcode`\_\active \def_#1_{\textcolor{blue}{#1}}%
}_\documentclass_{article}/_\begin_{document}/ We all love _\LaTeX_!/_\end_{document}|
\endgroup
который выводит
Не знаю, где вы об этом \@firstofone
изначально прочитали, но, возможно, это было в одном из таких контекстов.