我使用 xparse 和 expl3 定义了一个新宏来生成一组两个列表。这个想法是让一个宏具有与旧宏相同的输出,这对用户非常不友好,因为我必须为不同数量的条目编写一个宏。在 siunitx.dtx 的帮助下,我能够编写一个宏,它生成的输出与旧宏的输出非常相似,但尚不相等。如您所见,旧宏使用数学模式,这使得条目之间的距离略小。
可能是因为我没有完全理解 SplitList 的每一个细节和不同的控制序列,我无法找到一种方法将第一个列表的每个项目定义为 \text{A}、\textbf{B} 等等,以便输出可以处于数学模式。
有没有办法以当前代码为起点来实现这一点?
编辑:
第一个列表应该是强制性的,并且至少包含一个条目 - 如果是这种情况,则只应打印第一个列表(第一个列表中的条目“A”应打印“A”)
如果第一个列表中至少有两个条目,则第二个列表中必须有两个条目(第一个列表中的条目“A; B”要求第二个列表中有条目“1; 2”。这应该打印“A:B = 1:2”)。
因为数学模式中的字母默认是斜体,所以第一个列表中的条目应该包装在 \text{} 宏中。
(終結編輯)
\documentclass{article}
\usepackage{expl3}
\usepackage{xparse}
\usepackage{nccmath}
\usepackage{listingsutf8}
\usepackage{siunitx} % to be used
\usepackage{xspace}
\newcommand{\oldmacro}[6]{$\text{#1}:\text{#3}:\text{#5} = #2:#4:#6$\xspace} % for comparison
\ExplSyntaxOn
%%% defining token list variables -----------------------------------
\tl_new:N \l_firstlist_tl
\tl_new:N \l_firstlist_current_tl
\tl_new:N \l_secondlist_tl
\tl_new:N \l_secondlist_current_tl
\tl_new:N \l_firstlist_separator_tl
\tl_new:N \l_secondlist_separator_tl
\tl_new:N \l_first_second_separator_tl
%%%%% setting the separators
\tl_set:Nn \l_firstlist_separator_tl {~:~}
\tl_set:Nn \l_secondlist_separator_tl {~:~}
\tl_set:Nn \l_first_second_separator_tl {~=~}
%%% defining boolean variables -----------------------------------
\bool_new:N \l_print_first_bool
\bool_new:N \l_print_first_second_bool
\bool_new:N \l_print_first_second_list_bool
%%% defining macros -----------------------------------
\NewDocumentCommand{\newmacro}{ >{ \SplitList { ; } } m >{ \SplitList { ; } } g }
{
\detailed_checks_func:nn {#1}{#2}
\newmacro_process_func:nn {#1}{#2}
\xspace
}
\cs_new_protected:Npn \detailed_checks_func:nn #1#2
{
\bool_set_false:N \l_print_first_bool
\bool_set_false:N \l_print_first_second_bool
\tl_if_single:nTF {#1}
{\tl_if_eq:nnTF {#1} {{}}
{\textbf{Error~Message~1}}
{\IfNoValueTF {#2}
{\bool_set_true:N \l_print_first_bool}
{\tl_if_single:nTF {#2}
{\textbf{Error~Message~2}}
{\textbf{Error~Message~3}}
}
}
}
{\detailed_nosingle_checks_func:nn {#1}{#2}}
}
\cs_new_protected:Npn \detailed_nosingle_checks_func:nn #1#2
{
\IfNoValueTF {#2}
{\textbf{Error~Message~4}}
{\int_compare:nNnTF {\tl_count:n {#1}} = {\tl_count:n {#2}}
{\bool_set_true:N \l_print_first_second_bool}
{\int_compare:nNnTF {\tl_count:n {#1}} < {\tl_count:n {#2}}
{\textbf{Error~Message~3}}
{\int_compare:nNnTF {\tl_count:n {#1}} > {\tl_count:n {#2}}
{\textbf{Error~Message~5}}
{\textbf{Error~Message~6}}
}
}
}
}
\cs_new_protected:Npn \newmacro_process_func:nn #1#2
{
\bool_if:nT {\l_print_first_bool}
{\firstlist_output_func:n {#1}}
\bool_set_true:N {\l_print_first_second_list_bool} % needed for testing purposes
\bool_if:nT {\l_print_first_second_bool}
{
\bool_if:nT {\l_print_first_second_list_bool}
{
\tl_clear:N \l_firstlist_current_tl
\tl_clear:N \l_firstlist_tl
\tl_map_function:nN {#1} \firstlist_process_aux_func:n
\l_firstlist_tl
\l_firstlist_separator_tl
\l_firstlist_current_tl
\l_first_second_separator_tl
\tl_clear:N \l_secondlist_current_tl
\tl_clear:N \l_secondlist_tl
\tl_map_function:nN {#2} \secondlist_process_aux_func:n
\l_secondlist_tl
\l_secondlist_separator_tl
\l_secondlist_current_tl
}
}
}
%%% function for processing the firstlist -----
\cs_new_protected:Npn \firstlist_process_aux_func:n #1
{
\tl_if_empty:NTF \l_firstlist_tl
{\tl_set_eq:NN \l_firstlist_tl \l_firstlist_current_tl}
{
\tl_put_right:NV \l_firstlist_tl \l_firstlist_separator_tl
\tl_put_right:NV \l_firstlist_tl \l_firstlist_current_tl
}
\tl_set:Nn \l_firstlist_current_tl {\firstlist_output_func:n {#1}}
}
%%% function for printing the firstlist -----
\cs_new_protected:Npn \firstlist_output_func:n #1
{
{#1}
}
%%% function for processing the secondlist -----
\cs_new_protected:Npn \secondlist_process_aux_func:n #1
{
\tl_if_empty:NTF \l_secondlist_tl
{\tl_set_eq:NN \l_secondlist_tl \l_secondlist_current_tl}
{
\tl_put_right:NV \l_secondlist_tl \l_secondlist_separator_tl
\tl_put_right:NV \l_secondlist_tl \l_secondlist_current_tl
}
\tl_set:Nn \l_secondlist_current_tl {\secondlist_output_func:n {#1}}
}
%%% function for printing the secondlist -----
\cs_new_protected:Npn \secondlist_output_func:n #1
{
{#1}
}
\ExplSyntaxOff
\begin{document}
\section{Working Examples:}
\lstinline|\newmacro{A}|: \newmacro{A}\\
\lstinline|\newmacro{A;B;C;D}{1;2;3;4}|: \newmacro{A;B;C;D}{1;2;3;4}
\subsection{For Comparison:}
$A:B:C=1:2:3$\\
$\text{A}:\text{B}:\text{C}=1:2:3$ () \\
\oldmacro{A}{1}{B}{2}{C}{3} (\lstinline|\oldmacro{A}{1}{B}{2}{C}{3}|)\\
\newmacro{A;B;C}{1;2;3} (\lstinline|\newmacro{A;B;C}{1;2;3}|)\\
A : B : C = 1 : 2 : 3\\
\end{document}
答案1
如果要使用数学模式,请在数学模式下调用宏。
这是一个实现:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\newmacro}{mm}
{
\echo_newmacro:nn { #1 } { #2 }
}
\seq_new:N \l_echo_newmacro_first_seq
\seq_new:N \l_echo_newmacro_second_seq
\cs_new_protected:Nn \echo_newmacro:nn
{
\seq_set_split:Nnn \l_echo_newmacro_first_seq { ; } { #1 }
\seq_set_split:Nnn \l_echo_newmacro_second_seq { ; } { #2 }
\seq_use:Nn \l_echo_newmacro_first_seq { : }
=
\seq_use:Nn \l_echo_newmacro_second_seq { : }
}
\ExplSyntaxOff
\begin{document}
$\newmacro{A;B;C}{1;2;3}$
$\newmacro{A;B;C;D}{1;2;3;4}$
\end{document}
完整规范后的新版本
请注意,由于第二部分是可选的,因此应在方括号中指定。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\newmacro}{mo}
{
\IfNoValueTF{ #2 }
{
\mathrm{#1}
}
{
\echo_newmacro:nn { #1 } { #2 }
}
}
\seq_new:N \l_echo_newmacro_first_seq
\seq_new:N \l_echo_newmacro_second_seq
\cs_new_protected:Nn \echo_newmacro:nn
{
\seq_set_split:Nnn \l_echo_newmacro_first_seq { ; } { #1 }
\seq_set_split:Nnn \l_echo_newmacro_second_seq { ; } { #2 }
\int_compare:nTF
{
\seq_count:N \l_echo_newmacro_first_seq == \seq_count:N \l_echo_newmacro_second_seq
}
{% OK, the number of items is the same
\mathrm{ \seq_use:Nn \l_echo_newmacro_first_seq { : } }
=
\seq_use:Nn \l_echo_newmacro_second_seq { : }
}
{% Error
\msg_error:nnnn { echo/ratio } { wrong-number } { #1 } { #2 }
}
}
\msg_new:nnnn { echo/ratio } { wrong-number}
{
Wrong~number~of~items
}
{
You~have~specified~lists~of~different~lengths~"#1"~and~"#2"
}
\ExplSyntaxOff
\begin{document}
$\newmacro{A}$
$\newmacro{A;B;C}[1;2;3]$
$\newmacro{A;B;C;D}[1;2;3;4]$
$\newmacro{A}[1;2]$
\end{document}
最后一次调用触发错误:
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! echo/ratio error: "wrong-number"
!
! Wrong number of items
!
! See the echo/ratio documentation for further information.
!
! For immediate help type H <return>.
!...............................................
l.54 $\newmacro{A}[1;2]
$
? h
|'''''''''''''''''''''''''''''''''''''''''''''''
| You have specified lists of different lengths "A" and "1;2"
|...............................................