我正在尝试通过以下方式合并会员检查宏土拨鼠和菲利佩·奥莱尼克(感谢他们两人提供的巧妙解决方案)变成了另一个宏的参数:
\singleBox{\convertNumPhelypeOleinik{1}{1}{0}{2}{1.46}}{200}{24}{13} % this fails
\singleBox{\convertNumMarmot{1}{1}{0}{2}{1.46}}{200}{24}{13} % this fails too
这会导致以下错误消息:
Undefined control sequence. ...ypeOleinik{1}{1}{0}{2}{1.46}}{200}{24}{13}
Undefined control sequence. ...tNumMarmot{1}{1}{0}{2}{1.46}}{200}{24}{13}
以下是演示此问题的 MWE。有人能帮我解决这个问题吗?
\documentclass[tikz, border=0mm]{standalone}
\usepackage{tikz,xfp,expl3}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Solution by marmot https://tex.stackexchange.com/users/121799/marmot
% https://tex.stackexchange.com/a/501776/23594
\newif\ifmember
\makeatletter% for \@for see e.g. https://tex.stackexchange.com/a/100684/121799
%from https://tex.stackexchange.com/a/498576/121799
\newcommand{\MemberQ}[2]{\global\memberfalse%
\@for\next:=#1\do{\ifnum\next=#2\global\membertrue\fi}}
\makeatother
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Solution by Phelype Oleinik https://tex.stackexchange.com/users/134574/phelype-oleinik
% https://tex.stackexchange.com/a/501777/23594
\ExplSyntaxOn
\prg_new_conditional:Npnn \afp_int_ismember:nn #1#2 { p, T, F, TF }
{ \__afp_ismember_loop:nw {#1} #2 , \q_recursion_tail , \q_recursion_stop }
\cs_new:Npn \__afp_ismember_loop:nw #1#2,
{
\quark_if_recursion_tail_stop_do:nn {#2}
{ \prg_return_false: }
\int_compare:nNnTF {#1} = {#2}
{ \use_i_delimit_by_q_recursion_stop:nw { \prg_return_true: } }
{ \__afp_ismember_loop:nw {#1} }
}
\ExplSyntaxOff
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\singleBox}[4]{%
\fill(\fpeval{#1}mm,\fpeval{#2}mm) rectangle
(\fpeval{#1} mm + \fpeval{#3} mm,\fpeval{#2} mm - \fpeval{#4} mm);
}
\newcommand{\convertNum}[5]{%
\fpeval{#1<6 ? #3 + 9 + (#4 + #5)*(#1-1) + (#2-1) : 0}
}
\newcommand{\convertNumPhelypeOleinik}[5] %
{
\ExplSyntaxOn
\fpeval{ \afp_int_ismember_p:nn {1} {1,2,3,4,5} ? #3 + 9 + (#4 + #5)*(#1-1) + (#2-1) : 0 }
\ExplSyntaxOff
}
\newcommand{\convertNumMarmot}[5] %
{
\MemberQ{1,2,3,4,5,6}{#1}
\ifmember \fpeval{#3 + 9 + (#4 + #5)*(#1-1) + (#2-1)} \fi
}
\begin{document}
% Testing membeship using Phelype Oleinik's method
\ExplSyntaxOn
\fpeval{ \afp_int_ismember_p:nn {1} {1,2,3,4,5} ? 123 : 321 }\par
\ExplSyntaxOff
% Testing membeship using marmot's method
\MemberQ{1,2,3,4}{2}
\ifmember 2 is in list \fi
\MemberQ{1,2,3,4}{5}
\ifmember 5 is in list\else%
5 is not in the list\fi
\begin{tikzpicture}
\draw[draw=black] (0mm,0mm) rectangle (300 mm, 400 mm);
\singleBox{100}{200}{24}{13} % This works just fine
\singleBox{\convertNum{1}{1}{0}{2}{1.46}}{200}{24}{13} % This work just fine
\singleBox{\convertNumPhelypeOleinik{1}{1}{0}{2}{1.46}}{200}{24}{13} % this fails
\singleBox{\convertNumMarmot{1}{1}{0}{2}{1.46}}{200}{24}{13} % this fails too
\end{tikzpicture}
\end{document}
答案1
我们的常驻土拨鼠提出的宏很好,但不能使用,\fpeval
因为它依赖于不可扩展的操作(\memberfalse
和\membertrue
)。
标签\ExplSyntaxOn
和\ExplSyntaxOff
类似于\makeatletter
和\makeatother
:它们必须环绕使用该语法的代码expl3
,而不是在代码内部。
更好的编码:
\documentclass[border=0mm]{standalone}
\usepackage{tikz,xfp,xparse}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Solution by Phelype Oleinik https://tex.stackexchange.com/users/134574/phelype-oleinik
% https://tex.stackexchange.com/a/501777/23594
\ExplSyntaxOn
\prg_new_conditional:Npnn \afp_int_ismember:nn #1#2 { p, T, F, TF }
{
\__afp_ismember_loop:nw {#1} #2 , \q_recursion_tail , \q_recursion_stop
}
\cs_new:Npn \__afp_ismember_loop:nw #1#2,
{
\quark_if_recursion_tail_stop_do:nn {#2}
{ \prg_return_false: }
\int_compare:nNnTF {#1} = {#2}
{ \use_i_delimit_by_q_recursion_stop:nw { \prg_return_true: } }
{ \__afp_ismember_loop:nw {#1} }
}
\NewExpandableDocumentCommand{\convertNum}{mmmmm}
{
\fp_eval:n
{
\afp_int_ismember_p:nn {1} {1,2,3,4,5} ? #3 + 9 + (#4 + #5)*(#1-1) + (#2-1) : 0
}
}
\ExplSyntaxOff
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\singleBox}[4]{%
\fill(\fpeval{#1}mm,\fpeval{#2}mm) rectangle
(\fpeval{#1} mm + \fpeval{#3} mm,\fpeval{#2} mm - \fpeval{#4} mm)
}
\begin{document}
\begin{tikzpicture}
\draw[draw=black] (0mm,0mm) rectangle (300 mm, 400 mm);
\singleBox{100}{200}{24}{13};
\singleBox{\convertNum{1}{1}{0}{2}{1.46}}{200}{24}{13};
\end{tikzpicture}
\end{document}
答案2
我的宏确实“不可扩展”但我永远不会\fpeval
在坐标中使用tikzpicture
。这是因为 Ti钾Z 有一个非常强大的解析器,因此你可以直接将表达式传递给 Ti钾Z 会自动解析它们,所以你可以完全忽略所有这些“嘿,我的东西是可扩展的”讨论。特别是,声明一个可以像其他函数一样解析的函数相当简单。在我看来,生成的代码比普通 TimemberQ
的疯狂混合要优雅得多\fpeval
钾Z 解析。
\documentclass[tikz, border=0mm]{standalone}
\makeatletter
\pgfmathdeclarefunction{memberQ}{2}{%
\begingroup%
\edef\pgfutil@tmpb{0}%
\edef\pgfutil@tmpa{#2}%
\expandafter\pgfmath@member@i\pgfutil@firstofone#1\pgfmath@token@stop
\edef\pgfmathresult{\pgfutil@tmpb}%
\pgfmath@smuggleone\pgfmathresult%
\endgroup}
\def\pgfmath@member@i#1{%
\ifx\pgfmath@token@stop#1%
\else
\ifnum#1=\pgfutil@tmpa\relax%
\gdef\pgfutil@tmpb{1}%
%\typeout{#1=\pgfutil@tmpa}
\fi%
\expandafter\pgfmath@member@i
\fi}
\makeatother
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\singleBox}[4]{%
\fill({(#1)*1mm},{(#2)*1mm}) rectangle
({(#1+#3)*1mm},{(#2-#4)*1mm});
}
\begin{document}
\begin{tikzpicture}
\draw[draw=black] (0mm,0mm) rectangle (300 mm, 400 mm);
\singleBox{100}{200}{24}{13} % This works just fine
\pgfmathparse{memberQ({1,2,3,4,5,6,7,8,9,10,11},3)}
\typeout{\pgfmathresult}
\singleBox{ifthenelse(memberQ({1,2,3,5},3),200,300)}{200}{24}{13} % This works just fine
\end{tikzpicture}
\end{document}
附录:一个memberQ
似乎适用于任意列表的函数。
\documentclass[tikz, border=0mm]{standalone}
\makeatletter
\pgfmathdeclarefunction{memberQ}{2}{%
\begingroup%
\edef\pgfutil@tmpb{0}%
\edef\pgfutil@tmpa{#2}%
\expandafter\pgfmath@member@i\pgfutil@firstofone#1\pgfmath@token@stop
\edef\pgfmathresult{\pgfutil@tmpb}%
\pgfmath@smuggleone\pgfmathresult%
\endgroup}
\def\pgfmath@member@i#1{%
\ifx\pgfmath@token@stop#1%
\else
\edef\pgfutil@tmpc{#1}%
\ifx\pgfutil@tmpc\pgfutil@tmpa\relax%
\gdef\pgfutil@tmpb{1}%
%\typeout{#1=\pgfutil@tmpa}%
\fi%
\expandafter\pgfmath@member@i
\fi}
\makeatother
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{document}
\pgfmathparse{memberQ({3,4,5},3)}\pgfmathresult
\pgfmathparse{memberQ({3,4,5},1)}\pgfmathresult
\pgfmathparse{memberQ({"a","b","c"},1)}\pgfmathresult
\pgfmathparse{memberQ({"a","b","c"},"a")}\pgfmathresult
\end{document}