如何编写一个具有逗号分隔且数量可变的参数的宏?

如何编写一个具有逗号分隔且数量可变的参数的宏?

我想在 LaTeX2e 中编写一个宏\textcolor,它可以传递嵌入在另一个宏中的颜色模型 gray、rgb 或 cmyk 的值。指定的参数数量表示要使用的颜色模型;1 个参数表示 gray,3 个参数表示 rgb,4 个参数表示 cmyk 模型。我能够编写一个宏来执行我想要的操作,但参数以标准方式括在括号中。这是我通过修改答案编写的代码这里

\makeatletter  
\def\setmycolour#1{%  
\@ifnextchar\bgroup%  
    {\docolour{#1}}  
    {\dogray{#1}}  
}  
\def\dogray#1{This is gray hue #1.}  
\def\docolour#1#2#3{%  
\@ifnextchar\bgroup%  
    {\docmyk{#1}{#2}{#3}}  
    {\dorgb{#1}{#2}{#3}}  
}  
\def\dorgb#1#2#3{This is rgb colour #1,#2,#3.}  
\def\docmyk#1#2#3#4{This is cmyk colour #1,#2,#3,#4.}  
\makeatother

我使用宏作为

\setmycolour{0.85}\\
\setmycolour{1}{0}{0}\\
\setmycolour{1}{0}{0}{0}\

我想使用宏,例如,as\setmycolour{1,0,0}\setmycolour{0.85}。如何解析宏定义中的参数来执行此操作?上面的代码是获得我想要的效果的最佳方法吗?

答案1

我们对此颜色的评论仅用于演示。

\documentclass{article}
\usepackage[T1]{fontenc}

\makeatletter  
\def\setmycolour#1{\expandafter\setmycolour@i#1,,,,\@nil}
\def\setmycolour@i#1,#2,#3,#4,#5\@nil{% 
  \ifx$#2$ we have gray => #1 \else
    \ifx$#3$ we have a wrong color setting \else
      \ifx $#4$ we have a rgb setting => #1,#2,#3\else
                we have a cmyk setting =>#1,#2,#3,#4
      \fi
    \fi
  \fi 
}  
\makeatother

\begin{document}

\setmycolour{0.5}\par
\setmycolour{0.5,0.6}\par
\setmycolour{0.5,0.6,0.7}\par
\setmycolour{0.5,0.6,0.7,0.8}\par

\end{document}

答案2

LaTeX3 解决方案:

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\setmycolour}{ m }
  {
   \prg_case_int:nnn { \clist_length:n { #1 } }
     {
      {1}{ \dogray{#1} }
      {3}{ \dorgb{#1} }
      {4}{ \docmyk{#1} }
     }
     {OOPS}
  }
\ExplSyntaxOff

\def\dogray#1{This is gray hue #1.}
\def\dorgb#1{This is rgb colour #1.}
\def\docmyk#1{This is cmyk colour #1.}

\begin{document}
\setmycolour{0.85}\\
\setmycolour{1,0,0}\\
\setmycolour{1,0,0,0}

\end{document}

当然,在可接受的情况下执行的命令可以进行定制。

重要变更

由于expl32012 年夏季所做的更改,功能

\prg_case_int:nnn
\clist_length:n

应该改为

\int_case:nnn
\clist_count:n

使用相同的语法。

答案3

\documentclass{minimal}

\makeatletter

\def \setmycolour #1{
    \newcount \n
    \n = 0
    \setmycolour@ #1,\stopmarker ,
    \ifnum \n = 1
        This is gray hue (#1).
    \else \ifnum \n = 3
        This is rgb colour (#1).
    \else \ifnum \n = 4
        This is cmyk colour (#1).
    \else
        \message{Wrong number of values.}
    \fi\fi\fi
}

\def \stopmarker{EOV}

\def \setmycolour@ #1,{
    \edef \colorvalue{#1}
    \ifx \colorvalue \stopmarker
        \let \next = \relax
    \else
        \advance \n by 1
        \let \next = \setmycolour@
    \fi
    \next
}
\makeatother

\begin{document}

    \setmycolour{0.5}\par
    \setmycolour{0.5,0.6}\par
    \setmycolour{0.5,0.6,0.7}\par
    \setmycolour{0.5,0.6,0.7,0.8}\par

\end{document}

答案4

只是为了好玩,lpeg其中包含一个解析器的解决方案luaTeX

\documentclass{standalone}
\usepackage{luacode}

\begin{luacode*}
  lpeg = require('lpeg')

  digit = lpeg.R('09')
  dot = lpeg.P('.')
  number = (digit^1 * dot * digit^1) + digit^1
  comma = lpeg.P(',')

  csv = lpeg.Ct(lpeg.C(number) * (comma * lpeg.C(number))^0) / function (t)
     if #t == 1 then
        return '\\dogray{' .. tostring(t[1]) .. '}'
     else if #t == 3 then
           return '\\dorgb{' .. tostring(t[1]) .. '}{' .. tostring(t[2]) .. '}{' .. tostring(t[3]) .. '}'
        else if #t == 4 then
              return '\\docmyk{' .. tostring(t[1]) .. '}{' .. tostring(t[2]) .. '}{' .. tostring(t[3]) .. '}{'  .. tostring(t[4]) .. '}'
           end
        end
     end
     end

  function parse_and_make(s)
     tex.sprint(lpeg.match(csv,s))
  end
\end{luacode*}

\def\dogray#1{This is gray hue #1.}  
\def\dorgb#1#2#3{This is rgb colour #1,#2,#3.}  
\def\docmyk#1#2#3#4{This is cmyk colour #1,#2,#3,#4.}  

\def\setmycolor#1{%
  \directlua{parse_and_make("#1")}}

\begin{document}

\setmycolor{0.85}\\
\setmycolor{1,0,0}\\
\setmycolor{1,0,0,0}\
\end{document}

相关内容