我想创建一个宏“mymacro”,它返回一个包含两行的数组。该宏有两个变量,每个变量都是由“b”、“o”、“x”、“|”组成的字符串。这些字符串代表“blank”、“\bigcirc”、“\bigotimes”、“垂直线分割一行”。列数是任意的,等于两个变量之一中的“b,o,x”的数量,每个变量具有相同的列数。请注意,“|”不会影响列数。
例如,
\mymacro{|bo|x|}{o|x|b}
应该返回
\documentclass[amsmath]{article}
%for vertical line
\def\vl{\hfil\kern\arraycolsep\vline\kern-\arraycolsep\hfilneg}
\begin{document}
$
\begin{array}{cccc}
\vl& & \bigcirc \vl & \bigotimes \vl \\\cline{2-4}
&\bigcirc \vl& \bigotimes \vl &
\end{array}
$
\end{document}
本例是三列的情况。我参考了这个问题为垂直线。
我尝试应用类似问题,但我对Tex宏编程不熟悉,无法解决上述问题。
谢谢您的合作。
答案1
可通过添加字符翻译进行扩展。它使用标准array
环境。
这个想法是将输入更改|bo|x|
为
\multicolumn{1}{|c}{\__fukai_mymacro_char:n{b}} &
\multicolumn{1}{c|}{\__fukai_mymacro_char:n{o}} &
\multicolumn{1}{c|}{\__fukai_mymacro_char:n{x}}
其中最后一个函数转换b
为幻像,只是为了确保它与其他字符占据相同的空间,o
进入\bigcirc
和x
进入\bigotimes
。
搜索正则表达式的意思是:找到零个或一个|
后跟字母的 ,以及零个或一个|
。如上所示,将其替换为\multicolumn
。在多次替换的最后,我们需要删除不需要的尾随&
。
+1
通过检查参数并传递任何不是的内容来计算列数|
。
\documentclass{article}
\usepackage{array}
\ExplSyntaxOn
\NewDocumentCommand{\mymacro}{mm}
{
\fukai_mymacro:nn { #1 } { #2 }
}
\tl_new:N \l__fukai_mymacro_a_tl
\tl_new:N \l__fukai_mymacro_b_tl
\cs_new_protected:Nn \fukai_mymacro:nn
{
% normalize the input
\__fukai_mymacro_normalize:Nn \l__fukai_mymacro_a_tl { #1 }
\__fukai_mymacro_normalize:Nn \l__fukai_mymacro_b_tl { #2 }
% start the array with the suitable number of columns
\begin{array}
{
* { \int_max:nn { \__fukai_mymacro_count:n { #1 } } { \__fukai_mymacro_count:n { #1 } } } { c }
}
\tl_use:N \l__fukai_mymacro_a_tl
\\ \hline
\tl_use:N \l__fukai_mymacro_b_tl
\end{array}
}
\cs_new_protected:Nn \__fukai_mymacro_normalize:Nn
{
\tl_set:Nn #1 { #2 }
\regex_replace_all:nnN
{ (\|)??([[:alpha:]])(\|?) } % |<char>|
{ \c{multicolumn}\{1\}\{\1 c \3\}\{ \c{__fukai_mymacro_char:n}\{\2\} \} \& }
#1
\regex_replace_once:nnN { \& \Z } { } #1
}
% count the non-| characters
\cs_new:Nn \__fukai_mymacro_count:n
{
\int_eval:n { 0 + \str_map_function:nN { #1 } \__fukai_mymacro_ischar:n }
}
\cs_new:Nn \__fukai_mymacro_ischar:n
{
\str_if_eq:nnF { #1 } { | } { +1 }
}
% the translations
\cs_new:Nn \__fukai_mymacro_char:n
{
\str_case:nn { #1 }
{
{b}{\phantom{\bigcirc}}
{o}{\bigcirc}
{x}{\bigotimes}
}
}
\ExplSyntaxOff
\begin{document}
$\mymacro{|b|b|ooo|x|}{oooooo}$
\bigskip
$\mymacro{|bo|x|}{o|x|b}$
\bigskip
$
\begin{array}{ccc}
\multicolumn{1}{|c}{} & \multicolumn{1}{c|}{\bigcirc} & \multicolumn{1}{c|}{\bigotimes}
\\\hline
\multicolumn{1}{c|}{\bigcirc} & \multicolumn{1}{c|}{\bigotimes} & \multicolumn{1}{c}{}
\end{array}
$
\end{document}
在图像中,第三个数组是“手工制作的”,以显示结果与第二个数组完成的结果相同\mymacro
。
答案2
例如,你可以尝试下面的代码。这里使用了 TeX 原语。
\def\mymacro{\vbox\bgroup \mymacroA}
\def\mymacroA#1{\hbox{\mystrut\mymacroB#1\relax}\futurelet\next\mymacroE}
\def\mymacroB#1{\ifx\relax#1\else \mymacroC{#1}\expandafter\mymacroB\fi}
\def\mymacroC#1{\ifx b#1\mymacroD{}\fi
\ifx o#1\mymacroD{\bigcirc}\fi
\ifx x#1\mymacroD{\bigotimes}\fi
\ifx |#1\kern-.2pt\vrule\kern-.2pt\fi
}
\def\mymacroD#1{\hbox to2em{$\hss#1\hss$}}
\def\mymacroE{\ifx\next\bgroup\hrule\expandafter\mymacroA\else\egroup\fi}
\def\mystrut{\vrule height2ex depth1ex width0pt\relax}
%% test:
\mymacro{|bo|x|}{o|x|b}
\end
答案3
这种方法是,两行符号之间的水平线与两行中较长的一行一样长:
\makeatletter
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral\expandafter\@secondoftwo\string{\expandafter
\@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
\@secondoftwo\string}\expandafter\UD@stopromannumeral\@secondoftwo}{%
\expandafter\UD@stopromannumeral\@firstoftwo}%
}%
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
\newcommand\UD@symbolbox[1]{\vbox to2em{\vss\hbox to 2em{\hss#1\hss}\vss}}%
\@ifdefinable\UD@gobbletoexclam{\long\def\UD@gobbletoexclam#1!{}}%
\@ifdefinable\UD@replacefork{\long\def\UD@replacefork#1!|!b!o!x!#2#3!!!!{#2}}%
\@ifdefinable\UD@replaceloop{%
\long\def\UD@replaceloop#1#2#3\bizarre{%
\UD@CheckWhetherNull{#3}{#1{\phantom}\vrule}{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@gobbletoexclam#2!}{%
\UD@replacefork!#2!b!o!x!{\UD@replaceloop{\@gobble}}%
!|!#2!o!x!{#1{\phantom}\vrule\UD@symbolbox{$\hss$}\UD@replaceloop{\@firstofone}}%
!|!b!#2!x!{#1{\phantom}\vrule\UD@symbolbox{$\bigcirc$}\UD@replaceloop{\@firstofone}}%
!|!b!o!#2!{#1{\phantom}\vrule\UD@symbolbox{$\bigotimes$}\UD@replaceloop{\@firstofone}}%
!|!b!o!x!{\UD@replaceloop{#1}}%
!!!!%
}{\UD@replaceloop{#1}}#3\bizarre
}%
}%
}%
\@ifdefinable\UD@loopoverrows{%
\long\def\UD@loopoverrows#1#2#3#4#5\bizarre{%
%#1 - previous row
%#2 - separators in current iteration
%#3 - separators in consecutive iterations
%#4 - current row
%#5 - following rows
\UD@CheckWhetherNull{#5}{}{%
\@secondoftwo#2%
\vbox{%
\baselineskip=0pt \lineskip=0pt
\@firstoftwo#2%
\hbox{\hphantom{\UD@replaceloop{\@firstofone}#1{{}{}}\bizarre}}%
\hbox{\UD@replaceloop{\@firstofone}#4{{}{}}\bizarre}%
}%
\UD@loopoverrows{#4}{#3}{#3}#5\bizarre
}%
}%
}%
\newcommand\mymacro[1]{%
\vbox{\UD@loopoverrows{}{{}{}}{{\hrule}{\hrule height 0pt depth 0pt}}#1{{}{}}\bizarre}%
}%
\makeatother
\documentclass{article}
\begin{document}
\mymacro{
{|bo|x|}
{o|b|xo|b}
{x|o|b}
{o|x|b}
{o|x|b|oxbx}
{|x|b|x|}
}
\end{document}
带有 o/b/x 东西的矩形的高度和宽度在宏中编码\UD@symbolbox
。水平规则的高度/垂直规则的宽度不包含在这些矩形的测量中。如果不需要垂直规则,则该垂直规则是幻影。