目标

目标

这是我之前的一个问题然而,经过几个小时的失败后,我决定直接询问这个问题。

目标

为了支持包中的四种德语变格克雷夫特,我打算定义一个新命令\crefthevariantname,其用法如下:

\crefthevariantname{theorem}
  {
    {Satz}{Sätze}
    , Nominativ = [der]{Satz}[die]{Sätze}
    , Genitiv   = [des]{Satzes}[der]{Sätze}
    , Dativ     = [dem]{Satz}[den]{Sätzen}
    , Akkusativ = [den]{Satz}[die]{Sätze}
  }

理想情况下,它应该在内部将此输入转换为:

\crefthename{theorem}
  [
    \str_case:NnF \l__crefthe_variant_tl
      {
        { Nominativ } { der }
        { Genitiv   } { des }
        { Dativ     } { dem }
        { Akkusativ } { den }
      } { }
  ]
  {
    \str_case:NnF \l__crefthe_variant_tl
      {
        { Nominativ } { Satz }
        { Genitiv   } { Satzes }
        { Dativ     } { Satz }
        { Akkusativ } { Satz }
      } { Satz }
  }
  [
    \str_case:Nn \l__crefthe_variant_tl
      {
        { Nominativ } { die }
        { Genitiv   } { der }
        { Dativ     } { den }
        { Akkusativ } { die }
      } { }
  ]
  {
    \str_case:Nn \l__crefthe_variant_tl
      {
        { Nominativ } { Sätze }
        { Genitiv   } { Sätze }
        { Dativ     } { Sätzen }
        { Akkusativ } { Sätze }
      } { Sätze }
  }

我已经直接测试了上述代码并且它可以工作,所以剩下要做的就是实现这种转换。

我做了什么

目前,我已经成功解析输入,代码如下:

\keys_define:nn { crefthe-variant-parse }
  {
    , unknown .code:n = {
                          \seq_put_right:No \l__crefthe_variant_variant_seq { \l_keys_key_tl }
                          \__crefthe_variant_append_to_seq:w #1
                        }
  }

\bool_new:N \l__crefthe_variant_dafault_given_bool
\cs_new:Nn \crefthe_parse_variant_string:n
  % #1 = clist of configuration
  {
    \bool_set_false:N \l__crefthe_variant_dafault_given_bool
    \clist_map_inline:nn { #1 }
      {
        \str_if_in:nnTF { ##1 } { = }
          {
            \keys_set:nn { crefthe-variant-parse } { ##1 }
          }
          {
            \bool_set_true:N \l__crefthe_variant_dafault_given_bool
            \__crefthe_variant_set_default:w ##1
          }
      }
    \__crefthe_variant_create_prop_from_seq:n { article_singular }
    \__crefthe_variant_create_prop_from_seq:n { article_plural }
    \__crefthe_variant_create_prop_from_seq:n { singular }
    \__crefthe_variant_create_prop_from_seq:n { plural }
  }

\tl_new:N \l__crefthe_variant_default_article_singular_tl
\tl_new:N \l__crefthe_variant_default_article_plural_tl
\tl_new:N \l__crefthe_variant_default_singular_tl
\tl_new:N \l__crefthe_variant_default_plural_tl
\NewDocumentCommand \__crefthe_variant_set_default:w { O{} m O{} m }
  {
    \tl_set:Nn \l__crefthe_variant_default_article_singular_tl { #1 }
    \tl_set:Nn \l__crefthe_variant_default_article_plural_tl { #3 }
    \tl_set:Nn \l__crefthe_variant_default_singular_tl { #2 }
    \tl_set:Nn \l__crefthe_variant_default_plural_tl { #4 }
  }

\seq_new:N \l__crefthe_variant_variant_seq
\seq_new:N \l__crefthe_variant_article_singular_seq
\seq_new:N \l__crefthe_variant_article_plural_seq
\seq_new:N \l__crefthe_variant_singular_seq
\seq_new:N \l__crefthe_variant_plural_seq
\NewDocumentCommand \__crefthe_variant_append_to_seq:w { O{} m O{} m }
  {
    \seq_put_right:Nn \l__crefthe_variant_article_singular_seq { #1 }
    \seq_put_right:Nn \l__crefthe_variant_article_plural_seq { #3 }
    \seq_put_right:Nn \l__crefthe_variant_singular_seq { #2 }
    \seq_put_right:Nn \l__crefthe_variant_plural_seq { #4 }
  }

\cs_new:Nn \__crefthe_variant_create_prop_from_seq:n
  {
    \prop_clear_new:c { l__crefthe_variant_ #1 _prop }
    \int_step_inline:nn { \seq_count:c { l__crefthe_variant_ #1 _seq } }
      {
        \prop_put:cxx { l__crefthe_variant_ #1 _prop }
          { \seq_item:cn { l__crefthe_variant_variant_seq } { ##1 } }
          { \seq_item:cn { l__crefthe_variant_ #1 _seq } { ##1 } }
      }
  }

主要命令是。它将分别\crefthe_parse_variant_string:n解析默认行(没有 的行=,在上例中为{Satz}{Sätze})和其他行(如):Nominativ = [der]{Satz}[die]{Sätze}

  1. \__crefthe_variant_set_default:w解析默认行,将字符串保存到相应的\l__crefthe_variant_default_<type>_tl
  2. \__crefthe_variant_append_to_seq:w处理其他行,每次将字符串附加到相应的行中\l__crefthe_variant_<type>_seq

此外,虽然我不确定这是否会对最终的解决方案有所帮助,但有了这个@egreg 的回答,有一个\__crefthe_variant_create_prop_from_seq:n将一对seq影响转换为一个property列表的方法。

我不知道该怎么做

我希望能够实现其中[...] {...} [...] {...}的一部分\crefthe_pass_variant_string_to:n,然后将其传递给\crefthename{<name>}获得所需的结果。

但是,由于所有这些变量(无论是tl还是seq)都是可重用的,因此在转换为最终结果时,必须对其进行适当扩展,即存储它们的值而不是宏本身。但是,由于我没有控制扩展的经验,即使使用强大的expl3我也很难正确实现这一点。

我唯一的目的是实现主要目标,即将输入转换为可以被接受的东西\crefthename,即接收命令m O{} m O{} m。因此,如果您觉得我的想法很乏味,或者有其他更好的方法,请与我分享您的意见。

平均能量损失

下面是一个 MWE。由于问题实际上是关于宏调用和扩展的,因此我没有包含有关crefthe。在某些注释部分,您可能会看到我尝试使用马克斯·切尔诺夫'沙@egreg的代码。

\documentclass{article}

\begin{document}

\ExplSyntaxOn

\NewDocumentCommand \crefthevariantname { m m }
  {
    \crefthe_parse_variant_string:n { #2 }
    \crefthe_pass_variant_string_to:n { \crefthename {#1} }
  }

\keys_define:nn { crefthe-variant-parse }
  {
    , unknown .code:n = {
                          \seq_put_right:No \l__crefthe_variant_variant_seq { \l_keys_key_tl }
                          \__crefthe_variant_append_to_seq:w #1
                        }
  }

\bool_new:N \l__crefthe_variant_dafault_given_bool
\cs_new:Nn \crefthe_parse_variant_string:n
  % #1 = clist of configuration
  {
    \bool_set_false:N \l__crefthe_variant_dafault_given_bool
    \clist_map_inline:nn { #1 }
      {
        \str_if_in:nnTF { ##1 } { = }
          {
            \keys_set:nn { crefthe-variant-parse } { ##1 }
          }
          {
            \bool_set_true:N \l__crefthe_variant_dafault_given_bool
            \__crefthe_variant_set_default:w ##1
          }
      }
    \__crefthe_variant_create_prop_from_seq:n { article_singular }
    \__crefthe_variant_create_prop_from_seq:n { article_plural }
    \__crefthe_variant_create_prop_from_seq:n { singular }
    \__crefthe_variant_create_prop_from_seq:n { plural }
  }

\tl_new:N \l__crefthe_variant_default_article_singular_tl
\tl_new:N \l__crefthe_variant_default_article_plural_tl
\tl_new:N \l__crefthe_variant_default_singular_tl
\tl_new:N \l__crefthe_variant_default_plural_tl
\NewDocumentCommand \__crefthe_variant_set_default:w { O{} m O{} m }
  {
    \tl_set:Nn \l__crefthe_variant_default_article_singular_tl { #1 }
    \tl_set:Nn \l__crefthe_variant_default_article_plural_tl { #3 }
    \tl_set:Nn \l__crefthe_variant_default_singular_tl { #2 }
    \tl_set:Nn \l__crefthe_variant_default_plural_tl { #4 }
  }

\seq_new:N \l__crefthe_variant_variant_seq
\seq_new:N \l__crefthe_variant_article_singular_seq
\seq_new:N \l__crefthe_variant_article_plural_seq
\seq_new:N \l__crefthe_variant_singular_seq
\seq_new:N \l__crefthe_variant_plural_seq
\NewDocumentCommand \__crefthe_variant_append_to_seq:w { O{} m O{} m }
  {
    \seq_put_right:Nn \l__crefthe_variant_article_singular_seq { #1 }
    \seq_put_right:Nn \l__crefthe_variant_article_plural_seq { #3 }
    \seq_put_right:Nn \l__crefthe_variant_singular_seq { #2 }
    \seq_put_right:Nn \l__crefthe_variant_plural_seq { #4 }
  }

\cs_new:Nn \__crefthe_variant_create_prop_from_seq:n
  {
    \prop_clear_new:c { l__crefthe_variant_ #1 _prop }
    \int_step_inline:nn { \seq_count:c { l__crefthe_variant_ #1 _seq } }
      {
        \prop_put:cxx { l__crefthe_variant_ #1 _prop }
          { \seq_item:cn { l__crefthe_variant_variant_seq } { ##1 } }
          { \seq_item:cn { l__crefthe_variant_ #1 _seq } { ##1 } }
      }
  }

% \cs_new_protected:Nn \__crefthe_variant_map_dafault:nn
%   {
%     \str_if_eq:onT { \l__crefthe_variant_tl } { #1 }
%       {
%         \prg_break:n { #2 \use_none:n }
%       }
%   }
% \cs_new_protected:Nn \__crefthe_variant_map:nn
%   {
%     \str_if_eq:onT { \l__crefthe_variant_tl } { #1 }
%       {
%         \prg_break:n { #2 }
%       }
%   }
\cs_new:Nn \crefthe_pass_variant_string_to:n
  {
    \bool_if:NTF \l__crefthe_variant_dafault_given_bool
      {
        #1
        % [
        %   \prop_if_in:coTF { l__crefthe_variant_article_singular_prop } { \l__crefthe_variant_tl }
        %     {
        %       \prop_get:coN { l__crefthe_variant_article_singular_prop } { \l__crefthe_variant_tl } \l_tmpa_tl
        %       \tl_use:N \l_tmpa_tl
        %     }
        %     { \l__crefthe_variant_default_article_singular_tl }
        % ]
        % {
        %   \prop_if_in:coTF { l__crefthe_variant_singular_prop } { \l__crefthe_variant_tl }
        %     {
        %       \prop_get:coN { l__crefthe_variant_singular_prop } { \l__crefthe_variant_tl } \l_tmpa_tl
        %       \tl_use:N \l_tmpa_tl
        %     }
        %     { \l__crefthe_variant_default_singular_tl }
        % }
        % [
        %   \prop_if_in:coTF { l__crefthe_variant_article_plural_prop } { \l__crefthe_variant_tl }
        %     {
        %       \prop_get:coN { l__crefthe_variant_article_plural_prop } { \l__crefthe_variant_tl } \l_tmpa_tl
        %       \tl_use:N \l_tmpa_tl
        %     }
        %     { \l__crefthe_variant_default_article_plural_tl }
        % ]
        % {
        %   \prop_if_in:coTF { l__crefthe_variant_plural_prop } { \l__crefthe_variant_tl }
        %     {
        %       \prop_get:coN { l__crefthe_variant_plural_prop } { \l__crefthe_variant_tl } \l_tmpa_tl
        %       \tl_use:N \l_tmpa_tl
        %     }
        %     { \l__crefthe_variant_default_plural_tl }
        % }
      }
      {
        #1
        % [
        %   \seq_map_pairwise_function:NNN
        %     \l__crefthe_variant_variant_seq
        %     \l__crefthe_variant_article_singular_seq
        %     \__crefthe_variant_map:nn
        % ]
        % {
        %   \seq_map_pairwise_function:NNN
        %     \l__crefthe_variant_variant_seq
        %     \l__crefthe_variant_singular_seq
        %     \__crefthe_variant_map:nn
        % }
        % [
        %   \seq_map_pairwise_function:NNN
        %     \l__crefthe_variant_variant_seq
        %     \l__crefthe_variant_article_plural_seq
        %     \__crefthe_variant_map:nn
        % ]
        % {
        %   \seq_map_pairwise_function:NNN
        %     \l__crefthe_variant_variant_seq
        %     \l__crefthe_variant_plural_seq
        %     \__crefthe_variant_map:nn
        % }
      }
  }

\ExplSyntaxOff

Text in case of empty.

\end{document}

下面是一个带有具体示例的 MWE crefthe(由于字数限制,我只能省略部分代码% ...;如果需要,您可以在上面的 MWE 中找到相应的代码)。

\documentclass{article}

\usepackage{amsthm}
\usepackage{crefthe}
\newtheorem{testenv}{Testenv}

\begin{document}

\ExplSyntaxOn

\NewDocumentCommand \crefthevariantname { m m }
  {
    \crefthe_parse_variant_string:n { #2 }
    \crefthe_pass_variant_string_to:n { \crefthename {#1} }
  }

%...

\cs_new:Nn \crefthe_pass_variant_string_to:n
  {
    \bool_if:NTF \l__crefthe_variant_dafault_given_bool
      {
        #1
        % ...
      }
      {
        #1
        % ...
      }
  }

\ExplSyntaxOff

\crefthevariantname{testenv}
  {
    [0]{Zero}[00]{Zero}
    , Nominativ = [1]{One}[11]{Ones}
    , Genitiv   = [2]{Two}[22]{Twos}
    , Dativ     = [3]{Three}[33]{Threes}
    , Akkusativ = [4]{Four}[44]{Fours}
  }

\begin{testenv}\label{testenv:test}
    Environment for testing...
\end{testenv}

\crefthe{testenv:test}

\crefthe[variant=Nominativ]{testenv:test}

\crefthe[variant=Genitiv]{testenv:test}

\crefthe[variant=Dativ]{testenv:test}

\crefthe[variant=Akkusativ]{testenv:test}

\end{document}

预期结果将是,0 Zero <number>等等。我没有包括实际的介词或定冠词来测试冠词收缩,但我们希望扩展能够按预期进行。1 One <number>2 Two <number>


以防万一,以下是 的当前版本(截至 2023/07/20)crefthe。它包含命令选项的定义variant和相应的宏\l__crefthe_variant_tl

\NeedsTeXFormat{LaTeX2e}[2022-06-01]
\ProvidesExplPackage
  {crefthe}
  {2023/07/20} {}
  {Cross referencing with proper definite articles}

\keys_define:nn { crefthe }
  {
    , overwrite  .bool_set:N = \l__crefthe_overwrite_bool
    , overwrite  .initial:n  = { false }
    , nameinlink .bool_set:N = \l__crefthe_nameinlink_bool
    , nameinlink .initial:n  = { false }
    , unknown    .code:n     =
        { \PassOptionsToPackage { \CurrentOption } { cleveref } }
  }
\ProcessKeyOptions [ crefthe ]

\bool_if:NT \l__crefthe_nameinlink_bool
  {
    \PassOptionsToPackage { nameinlink } { cleveref }
  }

\RequirePackage { cleveref }
\RequirePackage { regexpatch }

\NewCommandCopy \crefthe_cref_original:w      \cref
\NewCommandCopy \crefthe_Cref_original:w      \Cref
\NewCommandCopy \crefthe_crefname_original:w  \crefname
\NewCommandCopy \crefthe_Crefname_original:w  \Crefname
\NewCommandCopy \crefthe_namecref_original:w  \namecref
\NewCommandCopy \crefthe_nameCref_original:w  \nameCref
\NewCommandCopy \crefthe_namecrefs_original:w \namecrefs
\NewCommandCopy \crefthe_nameCrefs_original:w \nameCrefs

\str_new:N \l__crefthe_tmpa_str

% \l__crefthe_prep_once_tl is for the "-" mode,
% that only passes the preposition to the first definite article;
% \l__crefthe_prep_each_tl is for the "+" mode,
% that passes the preposition to every definite article.
\tl_new:N \l__crefthe_prep_once_tl
\tl_new:N \l__crefthe_prep_each_tl

\bool_new:N \g__crefthe_uppercase_bool
\bool_new:N \g__crefthe_has_prep_bool

\NewDocumentCommand \crefthe { s t- t+ O{} m }
  {
    \bool_gset_false:N \g__crefthe_uppercase_bool
    \__crefthe_cref_general:NNNnnN #1 #2 #3 { #4 } { #5 } \crefthe_cref_original:w
  }
\NewDocumentCommand \Crefthe { s t- t+ O{} m }
  {
    \bool_gset_true:N \g__crefthe_uppercase_bool
    \__crefthe_cref_general:NNNnnN #1 #2 #3 { #4 } { #5 } \crefthe_Cref_original:w
  }

\NewDocumentCommand \namecrefthe { t- t+ O{} m }
  {
    \bool_gset_false:N \g__crefthe_uppercase_bool
    \__crefthe_cref_general:NNNnnN \c_false_bool #1 #2 { #3 } { #4 } \crefthe_namecref_original:w
  }
\NewDocumentCommand \nameCrefthe { t- t+ O{} m }
  {
    \bool_gset_true:N \g__crefthe_uppercase_bool
    \__crefthe_cref_general:NNNnnN \c_false_bool #1 #2 { #3 } { #4 } \crefthe_nameCref_original:w
  }
\NewDocumentCommand \namecrefsthe { t- t+ O{} m }
  {
    \bool_gset_false:N \g__crefthe_uppercase_bool
    \__crefthe_cref_general:NNNnnN \c_false_bool #1 #2 { #3 } { #4 } \crefthe_namecrefs_original:w
  }
\NewDocumentCommand \nameCrefsthe { t- t+ O{} m }
  {
    \bool_gset_true:N \g__crefthe_uppercase_bool
    \__crefthe_cref_general:NNNnnN \c_false_bool #1 #2 { #3 } { #4 } \crefthe_nameCrefs_original:w
  }

\keys_define:nn { crefthe-setting }
  {
    , variant       .tl_set:N           = \l__crefthe_variant_tl
    , unknown       .code:n             = {
                                            \bool_gset_true:N \g__crefthe_has_prep_bool
                                            \tl_set:No \l__crefthe_prep_tl { \l_keys_key_tl }
                                          }
  }

\cs_new_protected:Nn \__crefthe_cref_general:NNNnnN
  % #1 = star or not
  % #2 = -
  % #3 = +
  % #4 = key-value
  % #5 = label
  % #6 = original command, such as \crefthe_cref_original:w or \crefthe_Cref_original:w
  {
    \tl_set:Nn \l__crefthe_variant_tl {}
    \bool_gset_false:N \g__crefthe_has_prep_bool
    \tl_set:Nn \l__crefthe_prep_tl {}

    \keys_set:nn { crefthe-setting } { #4 }

    \bool_if:NTF #2
      { \tl_set:No \l__crefthe_prep_once_tl { \l__crefthe_prep_tl } }
      {
        \bool_if:NTF #3
          { \tl_set:No \l__crefthe_prep_each_tl { \l__crefthe_prep_tl } }
          {
            % \str_set:Nx fully expands \__crefthe_prep_mode: into a string,
            % then \str_case:Vn compares the value of the resulting string:
            \str_set:Nx \l__crefthe_tmpa_str { \__crefthe_prep_mode: }
            \str_case:Vn \l__crefthe_tmpa_str
              {
                { - } { \tl_set:No \l__crefthe_prep_once_tl { \l__crefthe_prep_tl } }
                { + } { \tl_set:No \l__crefthe_prep_each_tl  { \l__crefthe_prep_tl } }
              }
          }
      }
    \group_begin:
    \bool_if:NTF #1
      { #6 * { #5 } }
      { #6   { #5 } }
    \group_end:
    \tl_gclear:N \l__crefthe_prep_each_tl
  }

% \__crefthe_prep_mode: defines the default mode for supported languages
\cs_new:Nn \__crefthe_prep_mode:
  {
    \str_case:Vn \languagename
      {
        {french}        { + }
        {italian}       { + }
        {spanish}       { - }
        {portuguese}    { + }
        {brazilian}     { + }
      }
  }

\NewDocumentCommand \crefthename { m O{} m O{} m }
  {
    \__crefthe_name_general:nnnnnn { #1 } { #2 } { #3 } { #4 } { #5 } { c }
  }

\NewDocumentCommand \Crefthename { m O{} m O{} m }
  {
    \__crefthe_name_general:nnnnnn { #1 } { #2 } { #3 } { #4 } { #5 } { C }
  }

\cs_new:Npn \crefthe_retrieve_space: { \skip_horizontal:n { -\tex_fontdimen:D 2 \tex_font:D~plus -\tex_fontdimen:D 3 \tex_font:D~minus -\tex_fontdimen:D 4 \tex_font:D } }

\cs_new:Nn \crefthe_empty_adjust:n
  {
    \tl_if_blank:nTF { #1 }
      {
        \crefthe_retrieve_space:
      }
      {
        #1
      }
  }

\cs_new_protected:Nn \__crefthe_name_general:nnnnnn
  % #1 = environment name
  % #2 = singular definite article
  % #3 = singular name
  % #4 = plural definite article
  % #5 = plural name
  % #6 = c or C
  {
    \__crefthe_name_general_do:nnnnnn
      { #1 }
      { \crefthemark { \crefthe_empty_adjust:n { #2 } } }
      { \crefthe_empty_adjust:n { #3 } }
      { \crefthemark { \crefthe_empty_adjust:n { #4 } } }
      { \crefthe_empty_adjust:n { #5 } }
      { #6 }
  }

\cs_new_protected:Nn \__crefthe_name_general_do:nnnnnn
  {
    \use:c { crefthe_#6refname_original:w } { #1 } { #2 #3 } { #4 #5 }
    \bool_if:NT \l__crefthe_nameinlink_bool
      {
        \hook_gput_code:nnn { begindocument } { crefthe }
          {
            \crefthe_patch_format:nnnn { #6ref@#1@format } { #6ref@#1@name } { #2 } { #3 }
            \crefthe_patch_format:nnnn { #6ref@#1@format@first } { #6ref@#1@name@plural } { #4 } { #5 }
            \crefthe_patch_format:nnnn { #6refrange@#1@format } { #6ref@#1@name@plural } { #4 } { #5 }
            \crefthe_patch_format:nnnn { #6refrange@#1@format@first } { #6ref@#1@name@plural } { #4 } { #5 }
          }
      }
  }

\seq_new:N \g__crefthe_already_patched_seq

\cs_new_protected:Nn \crefthe_patch_format:nnnn
  % #1 = name of the format command
  % #2 = name of the command after the hyperlink beginning mark
  % #3 = new content before the mark
  % #4 = new content after the mark
  {
    \seq_if_in:NnF \g__crefthe_already_patched_seq { #1 - #2 }
      {
        \makeatletter
        \tl_set:No \l_tmpa_tl { #3 }
        \tl_set:No \l_tmpb_tl { #4 }
        \exp_args:Nc \regexpatchcmd { #1 }
          { (\cP\# .) \c{ #2 } }
          { \u{l_tmpa_tl} \1 \u{l_tmpb_tl} }
          { } { \msg_warning:nnn { crefthe } { format-patch-failed } { #1 } }
        \makeatother
        \seq_gput_right:Nn \g__crefthe_already_patched_seq { #1 - #2 }
      }
  }

\msg_new:nnn { crefthe }
  { format-patch-failed }
  { Failed~to~patch~the~format~"\iow_char:N \\#1"! }

\cs_generate_variant:Nn \text_lowercase:n { V }
\NewDocumentCommand \crefthemark { m }
  {
    \crefthe_contraction:Ve \l__crefthe_prep_each_tl
      { \crefthe_contraction:Vn \l__crefthe_prep_once_tl { #1 } }
    \tl_gclear:N \l__crefthe_prep_once_tl
    \tl_gset:Nx \l__crefthe_prep_each_tl
      { \text_lowercase:V \l__crefthe_prep_each_tl }
    \str_if_eq:eeF { \str_tail:n { #1 } } { ' } { ~ }
    \bool_gset_false:N \g__crefthe_uppercase_bool
  }

\prg_generate_conditional_variant:Nnn \str_case_e:nn { ev } { T, F, TF }
\cs_new:Nn \crefthe_contraction:nn
  {
    \exp_args:Ne \__crefthe_contraction:nnn
      { \text_lowercase:n { #2 } } { #1 } { #2 }
  }
\cs_generate_variant:Nn \crefthe_contraction:nn { V, Ve }
\cs_new:Nn \__crefthe_contraction:nnn
  {
    % #1 is \text_lowercase:n { #3 }
    % #2 is the preposition
    \tl_if_blank:nTF { #2 }
      { #3 }
      {
        \tl_if_exist:cTF { c_crefthe_contraction_rule_ \languagename _tl }
          {
            \exp_args:Ne \__crefthe_conditional_uppercase:n
              {
                \str_case_e:evF { #2~#1 }
                  { c_crefthe_contraction_rule_ \languagename _tl }
                  { #2~#1 }
              }
          }
          { #2~#3 }
      }
  }
\cs_new:Nn \__crefthe_conditional_uppercase:n
  {
    \bool_if:NTF \g__crefthe_uppercase_bool
      { \text_titlecase_first:n }
      { \use:n }
        { #1 }
  }

\NewDocumentCommand \crefthepatchname { m }
  {
    \clist_map_inline:nn { #1 }
      {
        \crefthe_patch_name:n { ##1 }
      }
  }

\cs_new:Nn \crefthe_patch_name:n
  {
    \tl_gput_left:cn { cref@#1@name        } { \crefthemark { \crefthe_empty_adjust:n {} } }
    \tl_gput_left:cn { cref@#1@name@plural } { \crefthemark { \crefthe_empty_adjust:n {} } }
    \tl_gput_left:cn { Cref@#1@name        } { \crefthemark { \crefthe_empty_adjust:n {} } }
    \tl_gput_left:cn { Cref@#1@name@plural } { \crefthemark { \crefthe_empty_adjust:n {} } }
  }

\hook_gput_code:nnn { begindocument/end } { crefthe }
  {
    \bool_if:NT \l__crefthe_overwrite_bool
      {
        \RenewCommandCopy \cref     \crefthe
        \RenewCommandCopy \Cref     \Crefthe
        \RenewCommandCopy \crefname \crefthename
        \RenewCommandCopy \Crefname \Crefthename
      }
  }

\tl_const:Nn \c_crefthe_contraction_rule_french_tl
  {
    { à~le   }     { au  }
    { à~les  }     { aux }
    { de~le  }     { du  }
    { de~les }     { des }
    { À~le   }     { Au  }
    { À~les  }     { Aux }
    { De~le  }     { Du  }
    { De~les }     { Des }
  }
\tl_const:Nn \c_crefthe_contraction_rule_ngerman_tl
  {
    { an~dem  }     { am   }
    { an~das  }     { ans  }
    { bei~dem }     { beim }
    { in~dem  }     { im   }
    { in~das  }     { ins  }
    { von~dem }     { vom  }
    { zu~dem  }     { zum  }
    { zu~der  }     { zur  }
    { An~dem  }     { Am   }
    { An~das  }     { Ans  }
    { Bei~dem }     { Beim }
    { In~dem  }     { Im   }
    { In~das  }     { Ins  }
    { Von~dem }     { Vom  }
    { Zu~dem  }     { Zum  }
    { Zu~der  }     { Zur  }
  }
\tl_const:Nn \c_crefthe_contraction_rule_italian_tl
  {
    { a~il   }     { al    }
    { a~lo   }     { allo  }
    { a~l'   }     { all'  }
    { a~la   }     { alla  }
    { di~il  }     { del   }
    { di~lo  }     { dello }
    { di~l'  }     { dell' }
    { di~la  }     { della }
    { da~il  }     { dal   }
    { da~lo  }     { dallo }
    { da~l'  }     { dall' }
    { da~la  }     { dalla }
    { in~il  }     { nel   }
    { in~lo  }     { nello }
    { in~l'  }     { nell' }
    { in~la  }     { nella }
    { su~il  }     { sul   }
    { su~lo  }     { sullo }
    { su~l'  }     { sull' }
    { su~la  }     { sulla }
    { a~i    }     { ai    }
    { a~gli  }     { agli  }
    { a~le   }     { alle  }
    { di~i   }     { dei   }
    { di~gli }     { degli }
    { di~le  }     { delle }
    { da~i   }     { dai   }
    { da~gli }     { dagli }
    { da~le  }     { dalle }
    { in~i   }     { nei   }
    { in~gli }     { negli }
    { in~le  }     { nelle }
    { su~i   }     { sui   }
    { su~gli }     { sugli }
    { su~le  }     { sulle }
    { A~il   }     { Al    }
    { A~lo   }     { Allo  }
    { A~l'   }     { All'  }
    { A~la   }     { Alla  }
    { Di~il  }     { Del   }
    { Di~lo  }     { Dello }
    { Di~l'  }     { Dell' }
    { Di~la  }     { Della }
    { Da~il  }     { Dal   }
    { Da~lo  }     { Dallo }
    { Da~l'  }     { Dall' }
    { Da~la  }     { Dalla }
    { In~il  }     { Nel   }
    { In~lo  }     { Nello }
    { In~l'  }     { Nell' }
    { In~la  }     { Nella }
    { Su~il  }     { Sul   }
    { Su~lo  }     { Sullo }
    { Su~l'  }     { Sull' }
    { Su~la  }     { Sulla }
    { A~i    }     { Ai    }
    { A~gli  }     { Agli  }
    { A~le   }     { Alle  }
    { Di~i   }     { Dei   }
    { Di~gli }     { Degli }
    { Di~le  }     { Delle }
    { Da~i   }     { Dai   }
    { Da~gli }     { Dagli }
    { Da~le  }     { Dalle }
    { In~i   }     { Nei   }
    { In~gli }     { Negli }
    { In~le  }     { Nelle }
    { Su~i   }     { Sui   }
    { Su~gli }     { Sugli }
    { Su~le  }     { Sulle }
  }
\tl_const:Nn \c_crefthe_contraction_rule_spanish_tl
  {
    { a~el  }      { al  }
    { de~el }      { del }
    { A~el  }      { Al  }
    { De~el }      { Del }
  }
\tl_const:Nn \c_crefthe_contraction_rule_portuguese_tl
  {
    { a~o   }      { ao  }
    { a~a   }      { à   }
    { a~os  }      { aos }
    { a~as  }      { às  }
    { de~o  }      { do  }
    { de~a  }      { da  }
    { de~os }      { dos }
    { de~as }      { das }
    { em~o  }      { no  }
    { em~a  }      { na  }
    { em~os }      { nos }
    { em~as }      { nas }
    { A~o   }      { Ao  }
    { A~a   }      { À   }
    { A~os  }      { Aos }
    { A~as  }      { Às  }
    { De~o  }      { Do  }
    { De~a  }      { Da  }
    { De~os }      { Dos }
    { De~as }      { Das }
    { Em~o  }      { No  }
    { Em~a  }      { Na  }
    { Em~os }      { Nos }
    { Em~as }      { Nas }
  }
\tl_const:Nx \c_crefthe_contraction_rule_brazilian_tl
  { \exp_not:V \c_crefthe_contraction_rule_portuguese_tl }

\endinput
%%
%% End of file `crefthe.sty'.

答案1

我想指出的是,我不太喜欢这个代码。我认为界面不干净,你应该改为\crefthename支持指定变体的可选参数。

但是下面的代码可以相当直接地实现你想要的效果。我们需要的变量太多了,但我希望 10 个变量还是可以的。可以对速度进行一些优化,然后\tl_item:Nn改用\exp_args:No \exp_not:o { \exp_after:wN \use_i:nnnn \l__crefthe_<variable>_tl }其他方法,但我怀疑这样做是否值得,因为代码有太多更严重的性能问题,优化无法改变。

无论如何,这里什么也没有:

\documentclass{article}

\usepackage{amsthm}
\usepackage{crefthe}
\newtheorem{testenv}{Testenv}

\begin{document}

\ExplSyntaxOn

\NewDocumentCommand \crefthevariantname { m m }
  {
    \crefthe_parse_variant:n { #2 }
    \crefthe_pass_variant_to:n { \crefthename {#1} }
  }

% sn: singular noun, pn: plural noun, sa: singular article, pa: plural article
\tl_new:N \l__crefthe_variant_sn_tl
\tl_new:N \l__crefthe_variant_pn_tl
\tl_new:N \l__crefthe_variant_sa_tl
\tl_new:N \l__crefthe_variant_pa_tl
\tl_new:N \l__crefthe_variant_default_sn_tl
\tl_new:N \l__crefthe_variant_default_pn_tl
\tl_new:N \l__crefthe_variant_default_sa_tl
\tl_new:N \l__crefthe_variant_default_pa_tl
\bool_new:N \l__crefthe_variant_default_bool
\cs_new_protected:Npn \crefthe_parse_variant:n #1
  {
    \tl_clear:N \l__crefthe_variant_singular_noun_tl
    \tl_clear:N \l__crefthe_variant_plural_noun_tl
    \tl_clear:N \l__crefthe_variant_singular_article_tl
    \tl_clear:N \l__crefthe_variant_plural_article_tl
    \tl_clear:N \l__crefthe_variant_default_sn_tl
    \tl_clear:N \l__crefthe_variant_default_pn_tl
    \tl_clear:N \l__crefthe_variant_default_sa_tl
    \tl_clear:N \l__crefthe_variant_default_pa_tl
    \bool_set_false:N \l__crefthe_variant_default_bool
    \keyval_parse:NNn
      \__crefthe_parse_variant_default:n
      \__crefthe_parse_variant_value:nn
      {#1}
  }
\tl_new:N \l__crefthe_parsed_tl
% this is wrong! That's not a document command, interface should be cleaner.
\NewDocumentCommand \__crefthe_variant_parser:w { O{} m O{} m }
  {
    \tl_set:Nn \l__crefthe_parsed_tl { {#1} {#2} {#3} {#4} }
    \use_none_delimit_by_q_stop:w
  }
\cs_new_protected:Npn \__crefthe_parse_variant_default:n #1
  {
    \bool_set_true:N \l__crefthe_variant_default_bool
    \__crefthe_variant_parser:w #1 {} {} \q_stop
    \tl_set:Nx \l__crefthe_variant_default_sa_tl
      { \tl_item:Nn \l__crefthe_parsed_tl {1} }
    \tl_set:Nx \l__crefthe_variant_default_sn_tl
      { \tl_item:Nn \l__crefthe_parsed_tl {2} }
    \tl_set:Nx \l__crefthe_variant_default_pa_tl
      { \tl_item:Nn \l__crefthe_parsed_tl {3} }
    \tl_set:Nx \l__crefthe_variant_default_pn_tl
      { \tl_item:Nn \l__crefthe_parsed_tl {4} }
  }
\cs_new_protected:Npn \__crefthe_parse_variant_value:nn #1#2
  {
    \__crefthe_variant_parser:w #2 {} {} \q_stop
    \tl_put_right:Nx \l__crefthe_variant_sa_tl
      { { \tl_to_str:n {#1} } { \tl_item:Nn \l__crefthe_parsed_tl {1} } }
    \tl_put_right:Nx \l__crefthe_variant_sn_tl
      { { \tl_to_str:n {#1} } { \tl_item:Nn \l__crefthe_parsed_tl {2} } }
    \tl_put_right:Nx \l__crefthe_variant_pa_tl
      { { \tl_to_str:n {#1} } { \tl_item:Nn \l__crefthe_parsed_tl {3} } }
    \tl_put_right:Nx \l__crefthe_variant_pn_tl
      { { \tl_to_str:n {#1} } { \tl_item:Nn \l__crefthe_parsed_tl {4} } }
  }

\cs_new_protected:Npn \crefthe_pass_variant_to:n #1
  {
    \use:e
      {
        \exp_not:n {#1}
        \bool_if:NTF \l__crefthe_variant_default_bool
          {
            [
              \exp_not:n { \str_case:NnF \l__crefthe_variant_tl }
                { \exp_not:o \l__crefthe_variant_sa_tl }
                { \exp_not:o \l__crefthe_variant_default_sa_tl }
            ]
            {
              \exp_not:n { \str_case:NnF \l__crefthe_variant_tl }
                { \exp_not:o \l__crefthe_variant_sn_tl }
                { \exp_not:o \l__crefthe_variant_default_sn_tl }
            }
            [
              \exp_not:n { \str_case:NnF \l__crefthe_variant_tl }
                { \exp_not:o \l__crefthe_variant_pa_tl }
                { \exp_not:o \l__crefthe_variant_default_pa_tl }
            ]
            {
              \exp_not:n { \str_case:NnF \l__crefthe_variant_tl }
                { \exp_not:o \l__crefthe_variant_pa_tl }
                { \exp_not:o \l__crefthe_variant_default_pa_tl }
            }
          }
          {
            [
              \exp_not:n { \str_case:Nn \l__crefthe_variant_tl }
                { \exp_not:o \l__crefthe_variant_sa_tl }
            ]
            {
              \exp_not:n { \str_case:Nn \l__crefthe_variant_tl }
                { \exp_not:o \l__crefthe_variant_sn_tl }
            }
            [
              \exp_not:n { \str_case:Nn \l__crefthe_variant_tl }
                { \exp_not:o \l__crefthe_variant_pa_tl }
            ]
            {
              \exp_not:n { \str_case:Nn \l__crefthe_variant_tl }
                { \exp_not:o \l__crefthe_variant_pa_tl }
            }
          }
      }
  }

\ExplSyntaxOff

\crefthevariantname{testenv}
  {
    [0]{Zero}[00]{Zero}
    , Nominativ = [1]{One}[11]{Ones}
    , Genitiv   = [2]{Two}[22]{Twos}
    , Dativ     = [3]{Three}[33]{Threes}
    , Akkusativ = [4]{Four}[44]{Fours}
  }

\begin{testenv}\label{testenv:test}
    Environment for testing...
\end{testenv}

\crefthe{testenv:test}

\crefthe[variant=Nominativ]{testenv:test}

\crefthe[variant=Genitiv]{testenv:test}

\crefthe[variant=Dativ]{testenv:test}

\crefthe[variant=Akkusativ]{testenv:test}

\end{document}

在此处输入图片描述

相关内容