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