我想在二维空间中用 创建一个点,\defpoint(1;2){A}
在三维空间中用创建一个点\defpoint(1;2;-5){A}
。我更喜欢使用 TeX 的解决方案,但看看 LaTeX3 在这种情况下是否有用会很有趣。我从未尝试过用 LaTeX3 编程。
我使用了;
和而不是,
,因为在法语中我想写:\defpoint(1,5;2,5){A}
而不是
\defpoint({1,5},{2,5}){A}
。
还有其他条件:
我想要 \defpoint(12;23){A}
,但又不想\defpoint({12};{23}){A}
代码示例,但它不遵守最后一个条件:
\documentclass{minimal}
\makeatletter
\def\defpoint(#1;#2{\@ifnextchar){\coor@ii(#1;#2}{\coor@iii(#1;#2}}
\def\coor@ii(#1;#2)#3{two coordinates: #1;#2 and #3}
\def\coor@iii(#1;#2;#3)#4{three coordinates: #1;#2;#3 and #4}
\makeatother
\begin{document}
\defpoint(1;2;3){A}
%\defpoint(12;13){B} % here we need defpoint({12};{13}){B}
\end{document}
下一个条件是一个真正的问题,而且它不是必需的;我想用
\defpoint({sin(45)};{cos(45)}){A}
来避免\defpoint(sin(45);cos(45)){A}
;但我知道这非常困难。使用 TikZ,我们在某些情况下需要使用括号。
评估表达式将会很有趣,一个好的解决方案也应该允许轻松评估
答案1
\documentclass{article}
\makeatletter
\def\defpoint#1#{\expandafter\defpoint@i#1;;\@nil}
\def\defpoint@i#1;#2;#3;#4\@nil#5{%
\ifx\relax#3\relax \defpoint@ii#1;#2\@nil{#5}\else\defpoint@iii#1;#2;#3\@nil{#5}\fi}
\def\defpoint@ii(#1;#2)\@nil#3{2D~co-ordinates~-~#1;#2,~mandatory~argument~-~'#3'\\}
\def\defpoint@iii(#1;#2;#3)\@nil#4{3D~co-ordinates~-~#1;#2;#3,~mandatory~argument~-~'#4'\\}
\makeatother
\begin{document}
\noindent
\defpoint(1;2){A}
\defpoint(12;13){B}
\defpoint(sin(45);cos(45)){A}
\defpoint(1;2;-5){A}
\end{document}
答案2
由于 LaTeX3 解决方案是可以接受的,因此我会使用xparse
。 的内部结构xparse
可以正确处理嵌套的可选参数括号或类似内容,因此\defpoint(sin(45);cos(45)){A}
不是问题。
你没有说是否\defpoint
需要可扩展。假设不需要,那么满足条件的解决方案是
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand \defpoint
{ > { \SplitArgument { 2 } { ; } } D ( ) { 0 ; 0 } m }
{ \defpoint_aux:nnnn #1 {#2} }
\cs_new_protected:Npn \defpoint_aux:nnnn #1#2#3#4
{
\IfNoValueTF {#3}
{ 2D~co-ordinates~-~(#1;#2),~mandatory~argument~-~'#4' \\ }
{ 3D~co-ordinates~-~(#1;#2;#3),~mandatory~argument~-~'#4' \\ }
}
\ExplSyntaxOff
\begin{document}
\noindent
\defpoint(1;2){A}
\defpoint(12;13){B}
\defpoint(sin(45);cos(45)){A}
\defpoint(1;2;-5){A}
\end{document}
我需要一个内部函数 ( \defpoint_aux:nnnn
) 来处理可变数量的坐标。 结果是\SplitArgument
将第一个参数最多分为两个;
标记,并且始终会产生三个 <平衡文本#1
>。辅助函数会将其作为、#2
和拾取#3
,因此我们可以测试二维相对3D 通过查看第三个参数是否是特殊\NoValue
标记。
我上面没有介绍过,但你也可以测试括号中的参数是否给出,以及它是否只包含一个参数(IE否;
),再次使用\IfNoValueTF
测试。
对于可扩展的方法,您需要做更多的工作,以及最新的副本xparse
(嵌套可选参数在我检查这个问题之前不具备可扩展性)。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\DeclareExpandableDocumentCommand \defpoint
{ D ( ) { 0 ; 0 } m }
{ \defpoint_aux:nn {#1} {#2} }
\cs_new:Npn \defpoint_aux:nn #1#2
{ \defpoint_aux:nw {#2} #1 ; \q_nil ; \q_stop }
\cs_new:Npn \defpoint_aux:nw #1#2 ; #3 ; #4 ; #5 \q_stop
{
\quark_if_nil:nTF {#4}
{ \defpoint_aux:nnnn {#2} {#3} { \NoValue } {#1} }
{ \defpoint_aux:nnnn {#2} {#3} {#4} {#1} }
}
\cs_new:Npn \defpoint_aux:nnnn #1#2#3#4
{
\IfNoValueTF {#3}
{ 2D~co-ordinates~-~(#1;#2),~mandatory~argument~-~'#4' \\ }
{ 3D~co-ordinates~-~(#1;#2;#3),~mandatory~argument~-~'#4' \\ }
}
\ExplSyntaxOff
\begin{document}
\noindent
\defpoint(1;2){A}
\defpoint(12;13){B}
\defpoint(sin(45);cos(45)){A}
\defpoint(1;2;-5){A}
\end{document}
内部结构的想法与其他人所建议的非常相似,只是我使用预构建测试来测试“夸克”(特殊标记)。同样,我还没有完全测试这里的输入,因此例如空的可选参数会导致问题。
答案3
使用 eTeX,您应该使用\scantokens
:
\documentclass{article}
\makeatletter
\def\defpoint{%
\edef\saved@catcode{\number\catcode`\;}%
\catcode`\;12
\begingroup
\catcode`\(1 \catcode`\)2 \catcode`\ 9
\defpoint@i
}
\def\defpoint@i#1{%
\endgroup
\endlinechar-1 \everyeof{\noexpand}%
\edef\coord@point{\scantokens{#1}}%
\expandafter\defpoint@ii\coord@point;\@nil
}
\def\defpoint@ii#1;#2;#3\@nil#4{%
\catcode`\;\saved@catcode\relax
\ifx\relax#3\relax
2 coordonn\'ees : #1 et #2
\else
3 coordonn\'ees : #1 ; #2 et \def@point@iii#3
\fi
puis le point : #4\par
}
\def\def@point@iii#1;{#1}
\makeatother
\begin{document}
\defpoint(12;13){M}
\defpoint( sin(30) ; cos(45) ; 4 ){A}
\end{document}
答案4
您的问题是;#2{
:
\def\defpoint(#1;#2{\@ifnextchar){\coor@ii(#1;#2}{\coor@iii(#1;#2}}
它告诉将下一个标记或平衡组存储在;
as之后#2
。如果您不将内容包装在那里,则{ }
只会取第一个标记/字符。因此,它仅在#2
只有一个字符时才有效,但在一般情况下则无效。您需要读取到的所有内容,)
然后测试;
其中是否包含 a。
以下代码读取第一个;
和之间的所有内容)
,在其后面添加一个;
带有一些的\relax
,然后使用第二个宏,该宏使用两个;
分隔的部分并以\relax
作为结束标记。然后它检查添加的是否;
仍然存在,这表明只有一个坐标。在这种情况下,#2
直接使用原始内容,因为现在读取的部分(#3
)将包含第一个添加的\relax
。
\documentclass{article}
\makeatletter
\def\defpoint(#1;#2){%
\@defpoint{#1}{#2}#2\relax;\relax\relax
}
\def\@defpoint#1#2#3;#4\relax#5{%
\ifx;#5\relax% is it the added the `;` or the trailing `\relax`?
\def\next{\coor@iii({#1};{#3};{#4})}%
\else
\def\next{\coor@ii({#1};{#2})}%
\fi
\next
}
\def\coor@ii(#1;#2)#3{two coordinates: #1;#2 and #3}
\def\coor@iii(#1;#2;#3)#4{three coordinates: #1;#2;#3 and #4}
\makeatother
\begin{document}
\defpoint(1;2;3){A}
\defpoint(12;23;34){B}
\defpoint(12;13){C}
\defpoint(1;3){D}
\end{document}
代码不是完全可扩展的,但可以这样写。不过,因为它似乎是一个定义,所以我认为它不是必需的。