嵌套 \ifnum 命令

嵌套 \ifnum 命令

我正在尝试使宏在 biblatex 字段中工作edition。逻辑如下:

  • 如果版本 =1,则有后缀 -li (1-li)
  • 如果 edition>1 且 edition<21 则有前缀 me- (me-15,me-20 ..etc)
  • 如果版本 = 40,60,80,100,200,...1000,也有前缀 me-
  • 其他情况下后缀 -e(31-e、21-e、129-e、1010-e)

这是一个有效的代码:

 \protected\def\mkbibmascord#1{%
 \ifnum #1=1 #1-li \else %
 \ifnum #1<21 %
\ifnum #1>1 me-#1 \fi \else %
\ifnum #1 = 40  me-#1 \else%
\ifnum #1 = 60  me-#1 \else%
\ifnum #1 = 80  me-#1 \else%
\ifnum #1 = 100 me-#1 \else %
\ifnum #1 = 200  me-#1 \else %
#1-e
\fi\fi\fi\fi\fi\fi\fi%
}%
\protected\def\mkbibordinal{\mkbibmascord}%
\protected\def\mkbibfemord{\mkbibmascord}%
\protected\def\mkbibneutord{\mkbibmascord}%

但是我该如何编写通用代码/改进上述代码?(不仅限于 200),因为假设日历中会有很多 if/fi-s

答案1

这是一个实现expl3

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\cs_new:Nn \georgian_ordinal:n
 {
  \int_compare:nTF { 1 < #1 < 21 }
   { me\mbox{-}#1 }
   { \georgian_ordinal_aux:n { #1 } }
 }

\cs_new:Nn \georgian_ordinal_aux:n
 {
  \int_case:nnF { #1 }
   {
    {    1 }{ #1\mbox{-}li }
    {   40 }{ me\mbox{-}#1 }
    {   60 }{ me\mbox{-}#1 }
    {   80 }{ me\mbox{-}#1 }
    {  100 }{ me\mbox{-}#1 }
    {  200 }{ me\mbox{-}#1 }
    {  300 }{ me\mbox{-}#1 }
    {  400 }{ me\mbox{-}#1 }
    {  500 }{ me\mbox{-}#1 }
    {  600 }{ me\mbox{-}#1 }
    {  700 }{ me\mbox{-}#1 }
    {  800 }{ me\mbox{-}#1 }
    {  900 }{ me\mbox{-}#1 }
    { 1000 }{ me\mbox{-}#1 }
  }
  { #1\mbox{-}e }
 }

\cs_set_eq:NN \mkbibmascord  \georgian_ordinal:n
\cs_set_eq:NN \mkbibordinal  \georgian_ordinal:n
\cs_set_eq:NN \mkbibfemord   \georgian_ordinal:n
\cs_set_eq:NN \mkbibneutcord \georgian_ordinal:n

\ExplSyntaxOff

\begin{document}

% a loop for testing
\ExplSyntaxOn
\int_step_inline:nnnn { 1 } { 1 } { 1010 } { \mkbibmascord { #1 } ~ }
\ExplSyntaxOff

\end{document}

我只显示 1 到 210 之间的测试:

在此处输入图片描述

如果解释了 1000 以上的数字的规则,也许可以做一些更有效的事情。

答案2

解决方案使用\ifnums 并使用\variants{num}{list}{true-text}{false-text}宏,如果 num 等于列表中的数字,则扩展为“true-text”,否则扩展为“false-text”。

\def\variants#1#2{\variantsA{#1}#2,,\end}
\def\variantsA#1#2,{\ifx,#2,\expandafter\variantsE \else
   \ifnum#1=#2 \variantsC \else
      \expandafter\expandafter\expandafter\variantsA
   \fi\fi{#1}}
\def\variantsC#1\end#2#3{\fi\fi#2}
\def\variantsE#1\end#2#3{#3}

\protected\def\mkbibmascord#1{%
   \ifnum#1<1 #1-e\else
   \ifnum#1=1 #1-li\else
   \ifnum#1<21 me-#1\else
   \variants{#1}{40,60,80,100,200,300,400,500,600,700,800,900,1000}{me-#1}{#1-e}%
   \fi\fi\fi
}

答案3

这个问题有两个相对独立的方面:

 1. how to organize gracefully a long list of `\ifnum..` clauses, 
 2. how to automatize over a list.

这里我不会深入讨论第二部分,下面的代码通过处理来自 package 的300, 400, .., 1000via来说明。这是可扩展的。并且测试本身使用循环(不可扩展)。例如,这里一行宏就足够了。出于懒惰,我使用了来自 的循环。\xintApplyUnbracedxinttools\xintForwipet's answerxinttools

我的回答主要是观察非常简单的宏:

\long\def\DoThis #1#2\OrThat #3{\fi #1}
\long\def\OrThat #1{#1}

可用于处理第1点。不再需要\fi\fi\fi\fi...\fi。并且保持了可扩展性。

\long\def\DoThis #1#2\OrThat #3{\fi #1}
\long\def\OrThat #1{#1}

% for the (optional) list manipulations in the code and in the Test
\input xinttools.sty

% Notice that this \georgianordinal is an expandable macro
\def\georgianordinal #1{%
   \ifnum #1=1  \DoThis{1-li}\fi
   \ifnum #1<21 \DoThis{me-#1}\fi
   \ifnum #1=40 \DoThis{me-#1}\fi
   \ifnum #1=60 \DoThis{me-#1}\fi
   \ifnum #1=80 \DoThis{me-#1}\fi
   \ifnum #1=100 \DoThis{me-#1}\fi
   \ifnum #1=200 \DoThis{me-#1}\fi
   \xintApplyUnbraced
        {\georgianordinalaux {#1}}
        {{300}{400}{500}{600}{700}{800}{900}{1000}}%
   \OrThat {#1-e}%
}

% notice the space before \ifnum, which is there to stop 
% an expansion done via \romannumeral-`0 by \xintApplyUnbraced
\def\georgianordinalaux #1#2{ \ifnum #1=#2 \DoThis{me-#1}\fi}

% Test:

\xintFor #1 in {\xintintegers} \do {%
     \georgianordinal {\the#1},
     \ifnum#1>1050 \expandafter\xintBreakFor\fi
}

\bye

在此处输入图片描述

相关内容