我正在尝试使宏在 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
解决方案使用\ifnum
s 并使用\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, .., 1000
via来说明。这是可扩展的。并且测试本身使用循环(不可扩展)。例如,这里一行宏就足够了。出于懒惰,我使用了来自 的循环。\xintApplyUnbraced
xinttools
\xintFor
wipet's answer
xinttools
我的回答主要是观察非常简单的宏:
\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