原始问题如下(这是对我遇到的问题的一个糟糕的简化,而且在编辑之前,它还包含重大语法错误)。引发这个问题的问题是为什么\test
和\ttest
工作,但\tttest
给出!软件包 pgfbasematrix 错误:单个“&”符号与错误的 catcode 一起使用。
\documentclass{beamer}
\usepackage{tikz}
\usetikzlibrary{matrix}
\def\test #1.{#1}
\def\ttest #1.{\node{#1}}
\def\tttest #1, #2.{\node{#1}; & \node{#2};}
\begin{document}
\begin{tikzpicture}
\matrix [draw,row sep=1cm,nodes=draw]
{\node {10}; & \node {5}; \\
\node {5}; & \node {\test 10.}; \\};
\end{tikzpicture}
\newpage
\begin{tikzpicture}
\matrix [draw,row sep=1cm,nodes=draw]
{\node {10}; & \ttest 5. ; \\
\node {5}; & \node {\test 10.}; \\};
\end{tikzpicture}
\newpage
\begin{tikzpicture}
\matrix [draw,row sep=1cm,nodes=draw]
{\tttest 10, 5. \\
\node {5}; & \node {\test 10.}; \\};
\end{tikzpicture}
\end{document}
原始问题:
假设 Bob(我们虚构的人物)整天都要使用 AMS-TeX 输入很长的方程组。可怜的 Bob 非常疲惫,但有一天他突然顿悟:TeX 之书!Bob 读了第 7 章和第 20 章,认为他解决了问题。
无需输入:
\begin{align*}
& 2x + & 10y =& 20 \\
& x - & y =& 10 \\
\end{align*}
Bob 创建了一个宏并认为问题已经解决:
\def\bobmacro #1, #2, #3{ & #1 & #2 & #3 \\}
\begin{align*}
\bobmacro{ 2x+, 10y=, 20}
\bobmacro{ x-, y, 10}
\end{align*}
但可惜的是!宏无法编译,Bob 怀疑问题出在 cat 代码上&
,也可能是//
。他知道他可以通过使用 来消除它们\string
,并且这样做代码可以编译,但结果仍然不是所期望的。
Bob 去 TeX.SE 看了关于\csname
和 的问题\scantokens
。最后一个问题看起来很有希望,但他在 Google 上找不到一个简单的例子。
Bob 似乎比刚开始时更加困惑。他想知道:是否有一种 TeX/LaTeX 或 e-TeX 方式来实现他的宏背后的想法?
答案1
塞尔吉奥,对不起,鲍勃使用了错误的工具,因为提供的对齐align
肯定不是线性系统所需要的。
类别代码与此问题无关,也\scantokens
无济于事;\string&
完全是错误的。问题是,除非以不太简单的方式定义宏,否则您无法拥有跨越对齐中的两个单元格的宏。
但是 Sergio,抱歉,Bob,有一个更好的方法,通过systeme
包提供。文档是法语的,但有很多例子。
\documentclass{article}
\usepackage{systeme}
\begin{document}
\[
\systeme{
2x + 10y = 20,
x - y = 10
}
\]
\end{document}
如果你不想要括号,请添加
\sysdelim..
在您的文档前言中或者\systeme
在您不想使用括号的命令之前。
问题发生重大变化后
这是 TikZ 和库的一个已知限制matrix
。& 符号非常特殊,不应该出现在环境中调用的参数或宏中tikzpicture
。解决方法是使用ampersand replacement
; 我一直都在使用它,尽管在前两个例子中它不是必需的。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix}
\def\test #1.{#1}
\def\ttest #1.{\node{#1}}
\def\tttest #1, #2.{\node{#1}; \& \node{#2};}
\begin{document}
\begin{tikzpicture}
\matrix [draw,row sep=1cm,nodes=draw,ampersand replacement=\&]
{\node {10}; \& \node {5}; \\
\node {5}; \& \node {\test 10.}; \\};
\end{tikzpicture}
\bigskip
\begin{tikzpicture}
\matrix [draw,row sep=1cm,nodes=draw,ampersand replacement=\&]
{\node {10}; \& \ttest 5. ; \\
\node {5}; \& \node {\test 10.}; \\};
\end{tikzpicture}
\bigskip
\begin{tikzpicture}
\matrix [draw,row sep=1cm,nodes=draw,ampersand replacement=\&]
{\tttest 10, 5. \\
\node {5}; \& \node {\test 10.}; \\};
\end{tikzpicture}
\end{document}
答案2
除了所有关于该方法是否合适的评论之外,上面的方法根本不起作用,因为它\bobmacro
被定义为一个带有 2 个分隔参数(用逗号分隔)的宏,后跟一个普通参数,但它随后被调用为一个带有单个参数的宏,因此需要这样调用它
\begin{align*}
\bobmacro 2x+, 10y=, {20}
\bobmacro x-, y, {10}
\end{align*}
在这种情况下,它会产生与原始完全相同的输出,align*
尽管输入语法非常奇怪。
我建议 Bob(我们的虚构人物)应该重读第 20 章(关于如何确定参数的部分),以了解他定义了什么以及如何改进语法。@fjbu 给出的答案显示了如何实现他的输入语法。
答案3
定义这样的宏没有任何实际意义:
\documentclass{article}
\usepackage{amsmath}
\makeatletter
\def\bobmacro#1{\expandafter\bobmacro@i#1\@nil}
\def\bobmacro@i#1,#2,#3\@nil{ & #1 & #2 & #3 \\}
\makeatother
\begin{document}
\begin{align}
\bobmacro{ 2x+, 10y=, 20}
\bobmacro{ x-, y, 10}
\end{align}
\begin{align}
2x+ 10y &= 20\\
x- y &= 10
\end{align}
\end{document}
您需要为最后一行使用不同的宏,align
不要像\\
末尾那样:
答案4
这是解决此问题的 LaTeX 方法。我同时使用pgffor
和mathtools
。使用这些包并不是完全必要的,但创建循环来迭代行并控制内部扩展会多一些工作\xdef
。
\documentclass{article}
\usepackage{amsmath,amssymb}
\usepackage{etoolbox}
\usepackage{pgffor}
\makeatletter
\let\bob@align\relax
\let\bob@row\relax
\def\bob@build@row#1{%%
\let\bob@row\relax
\foreach \myi in {#1}
{%%
\ifx\bob@row\relax
\xdef\bob@row{\myi}%%
\else
\xdef\bob@row{\bob@row & \myi}%%
\fi
}%%
\xdef\bob@row{\bob@row \noexpand\\}%%
}
\def\bobmacro#1{%%
\let\bob@align\relax
\foreach \myn in {#1}
{%%
\ifx\bob@align\relax
\expandafter\bob@build@row\expandafter{\myn}%%
\xdef\bob@align{\expandonce\bob@row}%%
\else
\expandafter\bob@build@row\expandafter{\myn}%%
\xdef\bob@align{\expandonce\bob@align \expandonce\bob@row}%%
\fi
}
\begin{align*}
\bob@align
\end{align*}
}
\makeatother
\begin{document}
\bobmacro{%%
{2x+, 10y=, 20},
{x-,y=,10}%%
}
compare with:
\begin{align*}
2x + & 10y = & 20 \\
x - & y= & 10
\end{align*}
\end{document}
这个想法是使用两个宏:
- 一个用于构建单独的行
- 另一个用于构建完成的
align*
环境。
你确实需要小心错误的空白裁剪和破坏事物:
\bobmacro{%%
{2x+, 10y=, 20},
{x-,y=,10}
}
看上去相当无害,但\pgffor
看到末尾的空格{x-,y=,10}
,然后不会去掉括号。