我一直尝试让宏发挥作用,但没有成功。
我想要一个函数\graf{}
接受以分号分隔的参数列表。这些参数需要传递给\xygraph
具有特定语法的函数。
我正在使用xparse
,它去掉了语法所需的括号,所以我做了以下事情
\NewDocumentCommand{\graf}{ >{ \SplitList{;} } m }{%
{%
\NewDocumentCommand{\func}{ m }{%
!\{##1\}*+\{\thenewcounter \}="\thenewcounter"%
\addtocounter{newcounter}{1}
}%
\ProcessList{#1}{\func}%
}%
}
的输出\graf{(0,0);(1,1)}
是完美的:它被处理为
!{(0,0)}*+{0}="0"
!{(1,1)}*+{1}="1"
不幸的是,当我尝试将所有这些传递给时\xygraph
,事情进展不顺利,我得到了错误"argument of \graf has an extra }"
。
\NewDocumentCommand{\graf}{ >{ \SplitList{;} } m }{%
{%
\NewDocumentCommand{\func}{ m }{%
!\{##1\}*+\{\thenewcounter \}="\thenewcounter"%
\addtocounter{newcounter}{1}
}%
\xygraph{!{<0cm,0cm>;<1cm,0cm>:<0cm,1cm>::}
\ProcessList{#1}{\func}%
}
}
}
我该如何解决这个问题?
PS:如果我根本不想做任何处理,它确实有效
\DeclareDocumentCommand \gra {m}{
\xygraph{%
!{<0cm,0cm>;<1cm,0cm>:<0cm,1cm>::}%
#1 }
但这违背了简化语法的目的。
编辑:
还需要为图添加一个边列表。它应该看起来像
\graf{(0,0);(1,1);(1,2)}{0-1;0-2;1-2}
应该翻译为
\xygraph{ !{<0cm,0cm>;<1cm,0cm>:<0cm,1cm>::} !{(0,0)}*+{0}="0" !{(1,1)}*+{1}="1" !{(1,2)}*+{2}="2" "0"-"1" "0"-"2" "1"-"2"}
但我还不够好,无法expl3
独自做出改变。
答案1
您不应该\func
在 的定义内进行定义\graf
。另一方面,问题有点复杂,因为\xygraph
希望看到其论点已经形成。
这是一种方法expl3
。
\documentclass{article}
\usepackage{xparse}
\usepackage[all,cmtip]{xy}
\ExplSyntaxOn
\NewDocumentCommand{\graf}{m}
{
\andy_graf_input:n { #1 }
}
\seq_new:N \l_andy_graf_input_seq
\tl_new:N \l_andy_graf_output_tl
\cs_new_protected:Nn \andy_graf_input:n
{
\seq_set_split:Nnn \l_andy_graf_input_seq { ; } { #1 }
\tl_clear:N \l_andy_graf_output_tl
\int_step_inline:nnnn { 0 } { 1 } { \seq_count:N \l_andy_graf_input_seq - 1 }
{
\tl_put_right:Nx \l_andy_graf_output_tl
{
!{\seq_item:Nn \l_andy_graf_input_seq { ##1 + 1 }}*+{##1}="##1"
}
}
\andy_graf_make:V \l_andy_graf_output_tl
}
\cs_new_protected:Nn \andy_graf_make:n
{% some trickery because of the colons
\exp_args:Nx \xygraph { !{ \tl_to_str:n { <0cm,0cm>;<1cm,0cm>:<0cm,1cm>:: } \exp_not:n { #1 } } }
}
\cs_generate_variant:Nn \andy_graf_make:n { V }
\ExplSyntaxOff
\begin{document}
With \texttt{\string\xygraph}: \xygraph{!{<0cm,0cm>;<1cm,0cm>:<0cm,1cm>::!{(0,0)}*+{0}="0"!{(1,1)}*+{1}="1"}}
With \texttt{\string\graf}: \graf{(0,0);(1,1)}
With \texttt{\string\graf}: \graf{(0,0);(1,0);(1,1)}
\end{document}
首先用分号分隔输入,然后准备所需的列表并传递给\xygraph
。
有一个小问题,因为后面的冒号\ExplSyntaxOn
不是通常的冒号(它们被视为字母,因为它们必须是函数名称的一部分。
新版本的边缘规范如下:
\documentclass{article}
\usepackage{xparse}
\usepackage[all,cmtip]{xy}
\ExplSyntaxOn
\NewDocumentCommand{\graf}{mm}
{
\andy_graf_input:nn { #1 } { #2 }
}
\seq_new:N \l_andy_graf_vertices_seq
\seq_new:N \l_andy_graf_edges_seq
\tl_new:N \l_andy_graf_vertices_tl
\tl_new:N \l_andy_graf_edges_tl
\tl_const:Nx \c_andy_graf_start_tl { !{ \tl_to_str:n { <0cm,0cm>;<1cm,0cm>:<0cm,1cm>:: } } }
\cs_new_protected:Nn \andy_graf_input:nn
{
% the vertices
\seq_set_split:Nnn \l_andy_graf_vertices_seq { ; } { #1 }
\tl_clear:N \l_andy_graf_vertices_tl
\int_step_inline:nnnn { 0 } { 1 } { \seq_count:N \l_andy_graf_vertices_seq - 1 }
{
\tl_put_right:Nx \l_andy_graf_vertices_tl
{~ % a space
!{\seq_item:Nn \l_andy_graf_vertices_seq { ##1 + 1 }}*+{##1}="##1"
}
}
% the edges
\seq_set_split:Nnn \l_andy_graf_edges_seq { ; } { #2 }
\tl_clear:N \l_andy_graf_edges_tl
\seq_map_function:NN \l_andy_graf_edges_seq \__andy_graf_edge:n
% make the graph
\andy_graf_make:VVV \c_andy_graf_start_tl \l_andy_graf_vertices_tl \l_andy_graf_edges_tl
}
\cs_new_protected:Nn \andy_graf_make:nnn
{% some trickery because of the colons
\xygraph
{
#1 % the start
#2 % the vertices
#3 % the edges
}
}
\cs_generate_variant:Nn \andy_graf_make:nnn { VVV }
\cs_new_protected:Nn \__andy_graf_edge:n
{
\tl_set:Nn \l__andy_graf_edge_tl { #1 }
\regex_replace_all:nnN { ([^\-]*) - (.*) \Z } { \ "\1"-"\2" } \l__andy_graf_edge_tl
\tl_put_right:NV \l_andy_graf_edges_tl \l__andy_graf_edge_tl
}
\ExplSyntaxOff
\begin{document}
With \texttt{\string\xygraph}:
\xygraph{
!{<0cm,0cm>;<1cm,0cm>:<0cm,1cm>::}
!{(0,0)}*+{0}="0"
!{(1,1)}*+{1}="1"
"0"-"1"
}
With \texttt{\string\graf}: \graf{(0,0);(1,1)}{0-1}
With \texttt{\string\graf}: \graf{(0,0);(1,0);(1,1)}{0-1;1-2;2-0}
\end{document}