版本 1:

版本 1:

假设我想写一个这样的宏:

\makelinesegment{1:1-1:2-2:2}

并且它是否变成了类似这样的:

\draw (1,1) -- (1,2) -- (2,2);

问题是,如何将其解析1:1-1:2-2:2为单一选项。

使用另一种语言你可以通过以下方式来解析它:

input.split('-').each(fn(frag){
  let parts = frag.split(':')
  # draw (parts[0], parts[1]), ...
})

想知道如何在 LaTeX 中做到这一点。

答案1

这是一个 expl3 实现。

\lineparser_make_line应该很容易理解,它在 处拆分参数-,执行 map 以转换a:b(a,b),然后使用\draw与 s 连接的序列进行调用--。坐标的拆分有点难看,因为是块:中的字母,因此如果直接用作参数分隔符,则会产生错误的 catcode。\ExplSyntaxOn\ExplSyntaxOff:

\documentclass{article}

\usepackage{xparse,expl3,tikz}

\ExplSyntaxOn
% We need
%\cs_new:Npn\__lineparser_transform_coords:w#1:#2\q_mark}{
% but the ":" is changed by\ExplSyntaxOn, so we have to use a trick to use the normal colon in the parameter
\use:x{\cs_new:Npn\exp_not:N\__lineparser_transform_coords:w##1\c_colon_str##2\exp_not:N\q_mark}{
  (#1,#2)
}
\seq_new:N\__lineparser_coordinates_seq
\seq_new:N\__lineparser_coordinates_transformed_seq
\cs_new:Nn\lineparser_make_line:n{
  \seq_set_split:Nnn\__lineparser_coordinates_seq{ - }{#1}
  \seq_set_map:NNn
    \__lineparser_coordinates_transformed_seq
    \__lineparser_coordinates_seq
    {
      \__lineparser_transform_coords:w##1\q_mark
    }
  \draw
    \seq_use:Nn
      \__lineparser_coordinates_transformed_seq
      { -- }
    ;
}
\NewDocumentCommand\makelinesegment{m}{
  \lineparser_make_line:n{#1}
}
\ExplSyntaxOff

\begin{document}
\pagenumbering{gobble}

\begin{tikzpicture}
  \makelinesegment{1:1-1:2-2:2}
\end{tikzpicture}

\end{document}

与 Phelype Oleiniks 的回答类似,有特殊的函数来处理逗号列表,因此如果\makelinesegment{1:1,1:2,2:2}要解析,你可以例如使用

\documentclass{article}

\usepackage{xparse,expl3,tikz}

\ExplSyntaxOn
% We need
%\cs_new:Npn\__lineparser_transform_coords:w#1:#2\q_mark}{
% but the ":" is changed by\ExplSyntaxOn, so we have to use a trick to use the normal colon in the parameter
\use:x{\cs_new:Npn\exp_not:N\__lineparser_transform_coords:w##1\c_colon_str##2\exp_not:N\q_mark}{
  (#1,#2)
}
\seq_new:N\__lineparser_coordinates_seq
\seq_new:N\__lineparser_coordinates_transformed_seq
\cs_new:Nn\lineparser_make_line:n{
  \seq_set_from_clist:Nn\__lineparser_coordinates_seq{#1}% <-- The change
  \seq_set_map:NNn
    \__lineparser_coordinates_transformed_seq
    \__lineparser_coordinates_seq
    {
      \__lineparser_transform_coords:w##1\q_mark
    }
  \draw
    \seq_use:Nn
      \__lineparser_coordinates_transformed_seq
      { -- }
    ;
}
\NewDocumentCommand\makelinesegment{m}{
  \lineparser_make_line:n{#1}
}
\ExplSyntaxOff

\begin{document}
\pagenumbering{gobble}

\begin{tikzpicture}
  \makelinesegment{1:1,1:2,2:2}
\end{tikzpicture}

\end{document}

这比 Phelype Oleinik 的原始 TeX 解决方案更长更冗长,但我认为它更容易理解。

答案2

版本 1:

我的答案是主要使用 TeX 基元。我知道还有其他方法可以做到这一点,尤其是使用 expl3,但我还没有做到,所以...

我定义了一个接受一个参数的主宏\makelinesegment,在示例中1:1-1:2-2:2

\makelinesegmentappends 将其参数传递给\@coordpair,它将以形式为的某些内容作为参数x:y-\@coordpair将采用xy坐标并将它们添加\this@path(x,y)--

\@coordpair到达输入末尾时(IE找到\empty:\empty-),它完成并返回\makelinesegment

到目前为止,我们已经通过(1,1)--(1,2)--(2,2)--.then\makelinesegment调用来从 中\gobblemm删除最后一个。--\this@path

最后,\makelinesegment调用\draw\this@path;

\documentclass{article}

\usepackage{tikz}

\makeatletter
\def\makelinesegment#1{%
  \def\this@path{}%
  \@coordpair#1-\empty:\empty-\@empty%
  \expandafter\gobblemm\this@path;
  \draw\this@path;
}
\def\gobblemm#1--;{\edef\this@path{#1}}
\def\@coordpair#1:#2-#3\@empty{%
  \ifx#1\empty
  \else
    \edef\this@path{\this@path(#1,#2)--}%
    \expandafter\@coordpair%
  \fi
  #3\@empty%
}
\makeatother

\begin{document}
\pagenumbering{gobble}

\begin{tikzpicture}
  \makelinesegment{1:1-1:2-2:2}
\end{tikzpicture}

\end{document}

版本 2:

正如我在评论中所说,这种表示法在使用负坐标时可能会(并且会)引起歧义。因此,我建议稍作修改:将-分隔坐标对的 替换为,。如下所示:1:1,1:2,2:2

解决方案变得更加简单,因为我们可以使用 LaTeX\@for来迭代逗号分隔的列表。

现在\makelinesegment宏只需将其参数传递给\@for,后者拆分坐标对并将它们传递给\@pair\@pair然后将坐标对附加(x,y)--\this@list

其余部分与第一个版本类似;\gobblemm删除最后一个--\makelinesegment调用\draw\this@path;

\documentclass{article}

\usepackage{tikz}

\makeatletter
\def\makelinesegment#1{%
  \def\this@path{}%
  \@for\@pair:=#1\do{%
    \expandafter\splitpair\@pair\@empty%
  }%
  \expandafter\gobblemm\this@path;%
  \draw\this@path;
}
\def\gobblemm#1--;{\edef\this@path{#1}}
\def\splitpair#1:#2\@empty{%
  \edef\this@path{\this@path(#1,#2)--}%
}
\makeatother

\begin{document}
\pagenumbering{gobble}

\begin{tikzpicture}
  \makelinesegment{1:1,1:2,2:2}
\end{tikzpicture}

\end{document}

答案3

没有提供测试文件(再次),所以我从另一个答案中借用了一个。对于这样一个简单的转换,你实际上不需要任何额外的解析代码,只需定义扩展以内联进行:

enter image description here

\documentclass{article}

\usepackage{tikz}

\def\makelinesegment#1{\draw\xmakelinesegment#1-\empty;}
\def\xmakelinesegment#1:#2-#3{%
(#1,#2)
\ifx\empty#3\else--\expandafter\xmakelinesegment\fi
#3}


\begin{document}
\pagenumbering{gobble}

\begin{tikzpicture}
 \makelinesegment{1:1-1:2-2:2}
\end{tikzpicture}

\end{document}

答案4

由于您想自己调整解析器,这里有一个简单但具有发展性的解决方案(在@Manuel 的帮助下),使用expl3正则表达式。这个解决方案解决了 Phelype Oleinik 提到的情况:1:1--1:-2-2:2以下 2 个-

\documentclass{article}

\usepackage{tikz,xparse}

\ExplSyntaxOn

\tl_new:N \l_bob_func_tl

\NewDocumentCommand \makelinesegment { m }
 {
  \pgfextra
  \tl_set:Nn \l_bob_func_tl { #1 }
  \regex_replace_all:nnN { ([0-9])- } { \1)--( } \l_bob_func_tl
  \regex_replace_all:nnN { : } { , } \l_bob_func_tl
  \exp_last_unbraced:NNV
  \endpgfextra
  (\l_bob_func_tl)
 }

\ExplSyntaxOff

\begin{document}

\tikz\draw\makelinesegment{1:1--1:2-2:2};

\end{document}

相关内容