
Я уже довольно давно использую латекс, но ограничиваюсь только самыми основами. Я стараюсь использовать пакеты, когда это возможно. Сейчас я пытаюсь написать несколько кодов сам, чтобы сделать свой латексный документ чище. Вот чего я хочу добиться:
Когда я определяю:
\symb{flow}{f_#1^#2}[a,b]
Я хочу иметь возможность использовать
\flow % outputs $f_a^b$
\flow[x,y] % outputs $f_x^y$
Обратите внимание, что количество индексов не обязательно должно быть равно 2, оно может быть равно 1 или больше 2.
Вот что у меня есть сейчас:
\NewDocumentCommand{\symb}{m m m}
{ \expandafter\NewDocumentCommand\csname#1\endcsname{>{\SplitList{,}}O{#3}}
{
% Not sure what I need to write here
}
}
По сути, я хочу иметь возможность использовать \symb{flow}{f_#1^#2}[a,b]
для определения макроса \flow
, который принимает необязательный аргумент, который представляет собой разделенные запятыми индексы переменной. В случае, если необязательный аргумент не указан, будут использоваться индексы по умолчанию (в данном случае a, b).
На Python это будет записано так:
def symb(expr, default):
def fn(*args):
if len(args) == 0:
return expr % args
else:
return expr % default
return fn
flow = symb('$f_%s^%s$', (a, b))
flow() % outputs $f_a^b$
flow(x, y) % outputs $f_x^y$
решение1
Вы можете это сделать, но не стоит брать Python за образец для программирования в LaTeX.
В LaTeX аргументы заключаются в фигурные скобки и не могут быть заменены списками запятых.
В любом случае, вот реализация с любым количеством аргументов в шаблоне (но вам, конечно, придется указать, сколько именно аргументов вы хотите).
\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\symb}{mmmm}
{% #1=name of command to define, #2=number of args, #3=template, #4=default
% define the internal version
\cs_new_protected:cn { kelvin_symb_#1:\prg_replicate:nn{#2}{n} } { #3 }
% define the external version
\exp_args:Nc \NewDocumentCommand { #1 } { O{#4} }
{
\__kelvin_symb_do:nnx { #1 } { #2 } { \clist_map_function:nN { ##1 } \__kelvin_symb_brace:n }
}
}
\cs_new:Nn \__kelvin_symb_do:nnn
{
\use:c { kelvin_symb_#1:\prg_replicate:nn{#2}{n} } #3
}
\cs_generate_variant:Nn \__kelvin_symb_do:nnn { nnx }
\cs_new:Nn \__kelvin_symb_brace:n { {#1} }
\ExplSyntaxOff
\symb{flow}{2}{f_{#1}^{#2}}{a,b}
\symb{foo}{4}{\int_{#1}^{#2}#3\,d#4}{0,1,x,x}
\begin{document}
$\flow$
$\flow[x,y]$
$\foo$
$\foo[a,b,f(x),x]$
\end{document}
Еще несколько слов о коде. Сначала о простых вещах:
\exp_args:Nc \NewDocumentCommand { #1 } { O{#4} }
это expl3
версия
\expandafter\NewDocumentCommand\csname#1\endcsname { O{#4 } }
и ему следует отдать предпочтение.
Далее описание того, как \symb
работает. Сначала он определяет внутреннюю функцию с таким количеством аргументов, как объявлено; ее заменяющий текст предоставляется заданным шаблоном. Таким образом, \symb{flow}{2}{f_{#1}^{#2}}{a,b}
определяет
\kelvin_symb_flow:nn { f_{#1}^{#2} }
Примечание. Нет никаких проблем с тем фактом, что _
это буква в области действия \ExplSyntaxOn
, поскольку декларация \symb{flow}{2}{...}{...}
данаснаружиэтот объем.
После этого мы определяем команду уровня пользователя \flow
с необязательным аргументом, по умолчанию которой используется четвертый аргумент \symb
. Эта команда косвенно вызывает ранее определенную функцию посредством \__kelvin_symb_do:nnx
.
Первый аргумент будет, в этом случае, flow
, второй — количество аргументов; их цель — иметь возможность вызвать внутреннюю функцию. Последний аргумент — список запятых (по умолчанию или тот, который задан как необязательный аргумент для \flow
), но предварительно обработанный так, чтобы он выдавал список элементов в скобках.
Обычная версия \__kelvin_symb_do:nnn
просто формирует внутреннюю функцию \kelvin_symb_flow:nn
и снимает скобки с третьего аргумента. Но мы используем ее вариант; когда
\clist_map_function:nN { #1 } \__kelvin_symb_brace:n
полностью развернут (из-за x
варианта), если применить к a,b
нему, то получим {a}{b}
. Таким образом, мы получаем
\kelvin_symb_flow:nn { a } { b }
и LaTeX с радостью расширяется, как обычно, до f_{a}^{b}
.
решение2
Например, вы можете использовать это:
\def\sdef#1{\expandafter\def\csname#1\endcsname}
\def\symb#1#2[#3,#4]{%
\sdef{#1}{\expandafter\futurelet\expandafter\next\csname#1:a\endcsname}%
\sdef{#1:a}{\ifx\next[\csname#1:b\expandafter\endcsname
\else \csname#1:b\endcsname[#3,#4]\fi}%
\sdef{#1:b}[##1,##2]{#2}%
}
\symb{flow}{f_#1^#2}[a,b]
$\flow$ and $\flow[x,y]$.
Вторая версия этого макроса реализует ваши требования из комментариев:
\def\sdef#1{\expandafter\def\csname#1\endcsname}
\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\def\symb#1#2[#3]{%
\sdef{#1}{\expandafter\futurelet\expandafter\next\csname#1:a\endcsname}%
\sdef{#1:a}{\ifx\next[\csname#1:b\expandafter\endcsname
\else \csname#1:c\endcsname #3,,,,,,,,\end \fi}%
\sdef{#1:b}[##1]{\def\paramslistA{#3,}\def\paramslistB{}\setparams ##1,\end,
\csname#1:c\expandafter\endcsname \paramslistB,,,,,,,,\end}%
\sdef{#1:c}##1,##2,##3,##4,##5,##6,##7,##8,##9\end{#2}%
}
\def\setparams #1,{\ifx\end#1%
\expandafter\addto\expandafter\paramslistB\expandafter{\paramslistA}%
\else \expandafter \setparamslist \paramslistA \end #1,%
\expandafter\setparams\fi}
\def\setparamslist#1,#2\end#3,{\def\paramslistA{#2}\addto\paramslistB{#3,}}
\symb{flow}{f_#1^#2}[a,b]
\symb{test}{test: 1=#1, 2=#2, 3=#3, 4=#4}[a,b,c,d]
$\flow$ and $\flow[x,y]$.
\test
\test[mmm]
\test[x,y,z]
Это решение отличается от решения egreg: вам не нужно expl3 cmplicated macros, используются только примитивы TeX.
решение3
Это похоже на Wipet, но делает аргумент symb обязательным, как обсуждалось в комментариях.
\documentclass{article}
\def\symb#1#2#3{%
\expandafter\def\csname x#1\endcsname##1##2{#2}%
\expandafter\newcommand\csname #1\endcsname[1][#3]{%
\expandafter\splitcomma\csname x#1\endcsname ##1\relax}}
\def\splitcomma#1#2,#3\relax{#1{#2}{#3}}
\begin{document}
\symb{flow}{f_#1^#2}{a,b}
$\flow$
$\flow[x,y]$
\end{document}
И версия, которая допускает несколько (до 8) записей в списке аргументов.
\documentclass{article}
\def\symb#1#2#3{%
\expandafter\def\csname x#1\endcsname##1##2##3##4##5##6##7##8##9{#2}%
\expandafter\newcommand\csname #1\endcsname[1][#3]{%
\expandafter\splitcomma\csname x#1\endcsname ##1,,,,,,,,,,\relax}}
\def\splitcomma#1#2,#3,#4,#5,#6,#7,#8,#9\relax{#1{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}\relax}
\begin{document}
\symb{flow}{f_#1^#2}{a,b}
\symb{flowb}{f_#1^#2g_#3^#4}{a,b,c,d}
$\flow$
$\flow[x,y]$
$\flowb$
$\flowb[x,y,w,z]$
\end{document}