为什么此代码无法成功解析日期字符串?

为什么此代码无法成功解析日期字符串?

为了练习 expl3,我尝试将数字日期字符串解析为法语。有一个接收形式为(或或,尚未完成)\mymodule_display_date_year_month_day:n的字符串,并尝试将其转换为法语文本。但是,它无法成功解析字符串并将三个整数传递给。yyyy-mm-ddyyyy-mmmm-ddyyyy-mm-dd\mymodule_display_date_year_month_day_french:nnn

这是我目前尝试过的方法。哪里出了问题?

\documentclass{article}

\usepackage[french,english]{babel}

\begin{document}

\selectlanguage{french}

\ExplSyntaxOn

\int_new:N \l__mymodule_year_int
\int_new:N \l__mymodule_month_int
\int_new:N \l__mymodule_day_int

\cs_new:Nn \mymodule_text_superscript:n { \textsuperscript { #1 } }


\cs_new_protected:Nn \mymodule_display_date_year_month_day:n
  {
    \regex_match:nnTF { \A \d{4}-\d{1,2}-\d{1,2} \Z } { #1 }
      {
        \__mymodule_parse_yyyymmdd:www #1 \q_stop
        \exp_args:Nx \cs_if_exist_use:cTF { mymodule_display_date_year_month_day_ \languagename :nnn }
          {
            { \l__mymodule_year_int }
            { \l__mymodule_month_int }
            { \l__mymodule_day_int }
          }
          { #1 }
      }
      {
        \regex_match:nnTF { \A \d{4}-\d{1,2} \Z } { #1 }
          {
            %%
          }
          {
            \regex_match:nnTF { \A \d{4}-\d{1,2}-\d{1,2} \Z } { #1 }
              {
                %%
              }
              { ?? }
          }
      }
  }

\cs_new:Npn \__mymodule_parse_yyyymmdd:www #1-#2-#3 \q_stop
  {
    \int_set:Nn \l__mymodule_year_int  { #1 }
    \int_set:Nn \l__mymodule_month_int { #2 }
    \int_set:Nn \l__mymodule_day_int   { #3 }
  }

\cs_new:Nn \mymodule_display_date_year_month_day_french:nnn
  {
    \mymodule_display_date_month_day_french:nn { #2 } { #3 }
    \c_space_tl
    #1
  }

\cs_new:Nn \mymodule_display_date_year_month_french:nn
  {
    \mymodule_display_date_month_french:n { #2 }
    \c_space_tl
    #1
  }

\cs_new_protected:Nn \mymodule_display_date_month_day_french:nn
  {
    \mymodule_display_date_day_french:n { #2 }
    \c_space_tl
    \mymodule_display_date_month_french:n { #1 }
  }

\cs_new:Nn \mymodule_display_date_month_french:n
  {
    \int_case:nnF { #1 }
    {
      { 1 }  { janvier   }
      { 2 }  { février   }
      { 3 }  { mars      }
      { 4 }  { avril     }
      { 5 }  { mai       }
      { 6 }  { juin      }
      { 7 }  { juillet   }
      { 8 }  { août      }
      { 9 }  { septembre }
      { 10 } { octobre   }
      { 11 } { novembre  }
      { 12 } { décembre  }
    } { #1 }
  }

\cs_new:Nn \mymodule_display_date_day_french:n
  {
    \int_case:nnF { #1 }
      {
        { 1 } { 1 \mymodule_text_superscript:n { er } }
      } { #1 }
  }



\mymodule_display_date_year_month_day:n {2021-06-03}



\ExplSyntaxOff
\end{document}

答案1

您收到一个错误:

! Missing number, treated as zero.
<to be read again> 
                   j

因为你的代码正在执行:

\mymodule_display_date_year_month_day_french:nnn
  \l__mymodule_year_int \l__mymodule_month_int \l__mymodule_day_int

定义如下\mymodule_display_date_year_month_day_french:nnn

\cs_new_protected:Nn \mymodule_display_date_year_month_day_french:nnn
  {
    \mymodule_display_date_month_day_french:nn { #2 } { #3 }
    \c_space_tl
    #1
  }

这只会“使用” #1,也就是\l__mymodule_year_int,相当于只输入:

using an \l__mymodule_year_int causes an error

您不能直接写出整数变量来使用它。您必须在它前面加上\int_use:N。因此,一种解决方案是写入\int_use:N #1该定义(以及当天的定义)。更好的解决方案是使用 -typeV扩展将整数变量的值传递V给宏,因此在宏内部您不必担心传递给它的数据类型:

\documentclass{article}

\usepackage[T1]{fontenc}
\usepackage[french,english]{babel}

\begin{document}

\selectlanguage{french}

\ExplSyntaxOn

\int_new:N \l__mymodule_year_int
\int_new:N \l__mymodule_month_int
\int_new:N \l__mymodule_day_int

\cs_new_protected:Nn \mymodule_text_superscript:n { \textsuperscript { #1 } }


\cs_new_protected:Nn \mymodule_display_date_year_month_day:n
  {
    \regex_match:nnTF { \A \d{4}-\d{1,2}-\d{1,2} \Z } { #1 }
      {
        \__mymodule_parse_yyyymmdd:www #1 \s_stop
        \cs_if_exist_use:cTF { mymodule_display_date_year_month_day_ \languagename :VVV }
          {
            \l__mymodule_year_int
            \l__mymodule_month_int
            \l__mymodule_day_int
          }
          { #1 }
      }
      {
        \regex_match:nnTF { \A \d{4}-\d{1,2} \Z } { #1 }
          {
            %%
          }
          {
            \regex_match:nnTF { \A \d{4}-\d{1,2}-\d{1,2} \Z } { #1 }
              {
                %%
              }
              { ?? }
          }
      }
  }

\cs_new_protected:Npn \__mymodule_parse_yyyymmdd:www #1-#2-#3 \s_stop
  {
    \int_set:Nn \l__mymodule_year_int  { #1 }
    \int_set:Nn \l__mymodule_month_int { #2 }
    \int_set:Nn \l__mymodule_day_int   { #3 }
  }

\cs_new_protected:Nn \mymodule_display_date_year_month_day_french:nnn
  {
    \mymodule_display_date_month_day_french:nn { #2 } { #3 }
    \c_space_tl
    #1
  }
\cs_generate_variant:Nn \mymodule_display_date_year_month_day_french:nnn { VVV }

\cs_new_protected:Nn \mymodule_display_date_year_month_french:nn
  {
    \mymodule_display_date_month_french:n { #2 }
    \c_space_tl
    #1
  }

\cs_new_protected:Nn \mymodule_display_date_month_day_french:nn
  {
    \mymodule_display_date_day_french:n { #2 }
    \c_space_tl
    \mymodule_display_date_month_french:n { #1 }
  }

\cs_new_protected:Nn \mymodule_display_date_month_french:n
  {
    \int_case:nnF { #1 }
    {
      { 1 }  { janvier   }
      { 2 }  { février   }
      { 3 }  { mars      }
      { 4 }  { avril     }
      { 5 }  { mai       }
      { 6 }  { juin      }
      { 7 }  { juillet   }
      { 8 }  { août      }
      { 9 }  { septembre }
      { 10 } { octobre   }
      { 11 } { novembre  }
      { 12 } { décembre  }
    } { #1 }
  }

\cs_new_protected:Nn \mymodule_display_date_day_french:n
  {
    \int_case:nnF { #1 }
      {
        { 1 } { 1 \mymodule_text_superscript:n { er } }
      } { #1 }
  }



\mymodule_display_date_year_month_day:n {2021-06-03}



\ExplSyntaxOff
\end{document}

答案2

我们不应忘记,我们还有更简单的编程语言:低级 TeX:

\def\monthdef#1 #2 {\expandafter\def\csname m:#1\endcsname{#2}}

\monthdef 1   janvier   
\monthdef 2   février   
\monthdef 3   mars      
\monthdef 4   avril     
\monthdef 5   mai       
\monthdef 6   juin      
\monthdef 7   juillet   
\monthdef 8   août      
\monthdef 9   septembre 
\monthdef 10  octobre   
\monthdef 11  novembre  
\monthdef 12  décembre  

\catcode`\_=11

\newcount\tmpnum
\def\display_date_year_month_day #1{\display_dateA #1;}
\def\display_dateA #1-#2-#3;{\tmpnum=#3\relax \the\tmpnum \
   \tmpnum=#2\relax \csname m:\the\tmpnum\endcsname \
   #1%
}

\display_date_year_month_day {2021-06-03}

\bye

答案3

你可以加快你的代码速度。你可以使用以下命令检查输入的正确性

\regex_match:nnTF { \A \d{4}-\d{1,2}(|-\d{1,2}) \Z } { #1 }

因此最后一组可能缺失了。

之后,您可以通过拆分输入\seq_set_split:Nnn并调用通用日期函数,并将当前语言(扩展)传递给该函数。

下一步是使用本地化版本。如果缺少日期,第三个参数将为 0,您可以在本地化函数中检查它。

\documentclass{article}

\usepackage[T1]{fontenc}
\usepackage[french,english]{babel}

\ExplSyntaxOn

% for testing
\NewDocumentCommand{\displaydate}{m}
  {
    \mymodule_display_date_year_month_day:n { #1 }
  }

\seq_new:N \l__mymodule_date_seq

\cs_new_protected:Nn \mymodule_text_superscript:n { \textsuperscript { #1 } }

\cs_new_protected:Nn \mymodule_display_date_year_month_day:n
  {
    \regex_match:nnTF { \A \d{4}-\d{1,2}(|-\d{1,2}) \Z } { #1 }
      {
        \seq_set_split:Nnn \l__mymodule_date_seq { - } { #1 }
        \mymodule_display_date_year_month_day:Veee
          \languagename
          { \seq_item:Nn \l__mymodule_date_seq { 1 } } % year
          { \seq_item:Nn \l__mymodule_date_seq { 2 } } % month
          { \seq_item:Nn \l__mymodule_date_seq { 3 } } % day
      }
      {
       ???#1???
      }
  }

\cs_new_protected:Nn \mymodule_display_date_year_month_day:nnnn
  {
    \use:c { __mymodule_display_date_#1:nnn } { #2 } { #3 } { \int_eval:n { 0#4 } }
  }
\cs_generate_variant:Nn \mymodule_display_date_year_month_day:nnnn { Veee }

\cs_new_protected:Nn \__mymodule_display_date_english:nnn
  {
    % month
    \int_case:nn { #2 }
      {
        { 1 }  { January   }
        { 2 }  { February  }
        { 3 }  { March     }
        { 4 }  { April     }
        { 5 }  { May       }
        { 6 }  { June      }
        { 7 }  { July      }
        { 8 }  { August    }
        { 9 }  { September }
        { 10 } { October   }
        { 11 } { November  }
        { 12 } { December  }
      }
    % day
    \int_compare:nF { #3 == 0 } { \nobreakspace #3 }
    % year
    ,\nobreakspace #1
  }

\cs_new_protected:Nn \__mymodule_display_date_french:nnn
  {
    % day
    \int_compare:nF { #3 == 0 } { \mymodule_display_date_day_french:n { #3 } \nobreakspace }
    % month
    \int_case:nn { #2 }
      {
        { 1 }  { janvier   }
        { 2 }  { février   }
        { 3 }  { mars      }
        { 4 }  { avril     }
        { 5 }  { mai       }
        { 6 }  { juin      }
        { 7 }  { juillet   }
        { 8 }  { août      }
        { 9 }  { septembre }
        { 10 } { octobre   }
        { 11 } { novembre  }
        { 12 } { décembre  }
      }
    \nobreakspace #1
  }

\cs_new_protected:Nn \mymodule_display_date_day_french:n
  {
    \int_case:nnF { #1 }
      {
        { 1 } { 1 \mymodule_text_superscript:n { er } }
      }
      { #1 }
  }

\ExplSyntaxOff


\begin{document}

\displaydate{abdarrr}

\displaydate{2021-06-03}

\displaydate{2021-06-01}

\displaydate{2021-06}

\selectlanguage{french}

\displaydate{2021-06-03}

\displaydate{2021-06-01}

\displaydate{2021-06}


\end{document}

在此处输入图片描述

相关内容