根据程序定义的基数选择语法形式(语言文本)

根据程序定义的基数选择语法形式(语言文本)

在许多语言中,语法形式取决于所描述的元素数量。在英语中,它是单数和复数形式(复数通常但并非总是通过添加后缀“s”来生成,但例如参见 mouse/mice),在其他语言中,它可能更复杂,按照 gettext 手册中所述

我想要的是一个根据数字选择语法形式的宏,例如\nn{\nmice}{mouse}{mice}对于英语,它将输出1 只小鼠2 只老鼠

对于波兰语,我还必须使用一些涉及条件和模数的整数计算包

Plural-Forms: nplurals=3; \
          plural=n==1 ? 0 : \
                 n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;

以及例如\nn{\nmice}{mysz}{mysze}{myszy}

上述公式(取自上述gettext 文档)意味着在波兰语中你有一 米斯(单数,第 0 种形式),2, 3, 4, 22, 23, 24 五月(保留旧双数形式、第一种复数形式),但5, 6, 7, 11, 12, 13, 14, 25 梅西(复数形式,第二种复数形式)。注意:斯洛文尼亚语有 4 种复数形式。

答案1

LuaTeX 非常适合此类宏。例如,这是 ConTeXt 中的实现(可以轻松转换为 LaTeX):

\startluacode
  -- Function to choose amoung n alternatives
  function commands.ngettext(n, f, t)
      -- The function f should return an integer 1, 2, etc.
      -- The table t contains the corresponding list of plurals
      context("%d %s", n, t[f(n)])
  end


\stopluacode

\define[1]\Mice
    {\ctxcommand{
        ngettext(#1, 
                  function(n) if n == 1 then return 1 else return 2 end; end,
                  {"mouse", "mice"})}}

\define[1]\Mysz
    {\ctxcommand{
        ngettext(#1, 
                  function(n) 
                    if n == 1 then 
                      return 1
                    elseif n \letterpercent 10 >= 2 and n \letterpercent 10<=4 and (n \letterpercent 100<10 or n \letterpercent 100 >= 20)  then
                      return 2
                    else 
                      return 3
                    end
                  end,
                  {"mysz", "mysze", "myszy"})}}
\starttext
Mouse: \Mice{1} \Mice{11} \Mice{22}

Mysz:   \Mysz{1} \Mysz{11} \Mysz{22}
\stoptext

这使

在此处输入图片描述

答案2

从您所指出的方法来看ngettext,似乎复数方案的数量有限,因此应该独立于给定单词的复数列表来定义这些方案。

以下是复数方案的一些示例。为了提高性能,复数方案是expl3直接使用命令定义的,而不是解析您建议的语法。可以\plural_new_scheme:nn

\cs_new_protected:Npn \plural_new_scheme:nn #1#2 % <scheme> <code>
  { \cs_new:cpn { __plural_scheme_#1:n } ##1 { \fp_to_int:n { #2 + 1 } } }

然后简单地将复数方案定义中的所有n内容替换为#1(例如#1==1?0:1#1>1,使用您在 C 中习惯使用的运算符)。

\documentclass{article}
\usepackage{expl3,xparse}

%%%%%%%%%%%%% Definitions first
\ExplSyntaxOn
% Defining and using a plural scheme
\cs_new_protected:Npn \plural_new_scheme:nn #1#2 % <scheme> <code>
  { \cs_new:cpn { __plural_scheme_#1:n } ##1 {#2} }
\cs_new:Npn \plural_scheme:nn #1#2 % <scheme> <value>
  { \use:c { __plural_scheme_#1:n } {#2} }
\cs_generate_variant:Nn \plural_scheme:nn { v }
% Defining and using a new word
\cs_new_protected:Npn \plural_new_word:nnn #1#2#3
  {
    \tl_const:cn { c__plural_word_#1_scheme_tl } {#2}
    \clist_const:cn { c__plural_word_#1_clist } {#3}
  }
\cs_new:Npn \plural_word:nn #1#2
  {
    \clist_item:cn { c__plural_word_#1_clist }
      { \plural_scheme:vn { c__plural_word_#1_scheme_tl } {#2} }
  }
%
\NewDocumentCommand \NW { mmm } % <new word> <plural scheme> <plural forms>
  { \plural_new_word:nnn {#1} {#2} {#3} }
\NewDocumentCommand \UW { mm } % 'use word' <word> <number>
  { \plural_word:nn {#1} {#2} }
\ExplSyntaxOff
%%%%%%%%%%%%%%%%%%%%%%%%


%%%%%%%%%%%%% Some pluralization schemes:
% 'n' comes as '#1', return values must start at 1.
\ExplSyntaxOn
\plural_new_scheme:nn { en } % English
  { \int_compare:nTF { #1 = 1 } { 1 } { 2 } }
\plural_new_scheme:nn { ro } % Romanian
  {
    \int_case:nnF {#1}
      {
        { 1 } { 1 } % if #1 is 1, then return 1
        { 0 } { 2 } % if #1 is 0, then return 2
      }
      { \int_compare:nTF { 0 < \int_mod:nn {#1} { 100 } < 20 } { 2 } { 3 } }
  }
\plural_new_scheme:nn { ru } % Russian
  {
    \bool_if:nTF
      {
        \int_compare_p:n { \int_mod:nn {#1} {10} = 1 }
        && \int_compare_p:n { \int_mod:nn {#1} {100} != 11 }
      }
      { 1 }
      {
        \bool_if:nTF
          {
            \int_compare_p:n { 2 <= \int_mod:nn {#1} {10} <= 4 }
            && ! \int_compare_p:n { 10 <= \int_mod:nn {#1} {100} < 20 }
          }
          { 2 }
          { 3 }
      }
  }
\ExplSyntaxOff
%%%%%%%%%%%%%%%%

\NW{mouse}{en}{mouse,mice}
\NW{mysz}{ru}{mysz,mysze,myszy}
\begin{document}
\UW{mouse}{0}, \UW{mouse}{1}, \UW{mouse}{2}, \UW{mouse}{36}!\
\UW{mysz}{0}, \UW{mysz}{1}, \UW{mysz}{2}, \UW{mysz}{104}!
\end{document}

答案3

针对每个单词单独进行强力解决,这里是 mysz。 (嘿,哈哈)

\documentclass{article}
\usepackage{polski}
\usepackage[cp1250]{inputenc}
\begin{document}

\def\mysz#1{\ifcase#1 myszy\or mysz \or mysze (naprawdę istnieje liczba podwójna?) \or myszy \else myszy \fi}

\mysz0
\mysz1
\mysz2
\mysz{126}

\end{document}

mysz被 替换时pani,就变得复杂了。0 pań, 4 panie, 14 pań, 24 panie, 25 pań 等。并且człowiek只有两种形式。如果你计划的字数有限,那没问题,但通常这可能是一项艰巨的工作。

答案4

下面是波兰语的纯 TeX 解决方案(基于模数计算这个答案)。为其他斯拉夫语言开发类似的宏留给读者作为练习。

\newcount\moduloResult
\def\modulo#1#2{%
  \moduloResult=#1
  \divide\moduloResult by #2
  \multiply\moduloResult by -#2
  \advance\moduloResult by #1\relax}

\def\pluralizePOL#1#2#3#4{%
  \def\many{#4}%
  \def\few{#3}%
  \ifnum#1=1\def\one{#2}\else\let\one\many\fi
  \modulo{#1}{100}%
  \ifnum\moduloResult>10\ifnum\moduloResult<20\let\few\many\fi\fi
  \modulo{#1}{10}%
  #1~\ifcase\moduloResult\many\or\one\or\few\or\few\or\few\else\many\fi}

\def\test#1{\pluralizePOL{#1}{jajo}{jaja}{jaj}, }

\test{0}\test{1}\test{2}\test{3}\test{4}\test{5}\par
\test{10}\test{11}\test{12}\test{15}\par
\test{20}\test{21}\test{22}\test{25}\par
\test{100}\test{101}\test{102}\test{105}\par
\test{110}\test{111}\test{112}\test{115}\par
\test{120}\test{121}\test{122}\test{125}\par
\bye

相关内容