假设date
是 ISO 格式的(YYYY-MM-DD
),我如何将其各个部分解析为变量?
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\int_new:N \mytest_date_day_int
\int_new:N \mytest_date_month_int
\int_new:N \mytest_date_year_int
\keys_define:nn { note-verbale } {
date .code:n = { }, % ???
}
\NewDocumentCommand \Information { m } {
\keys_set:nn { note-verbale } { #1 }
}
\NewDocumentCommand \PrintDate { } {
Date:\nobreakspace
\int_use:N \mytest_date_day_int
\slash
\int_use:N \mytest_date_month_int
\slash
\int_use:N \mytest_date_year_int
}
\ExplSyntaxOff
\Information{
date = 2015-02-10,
}
\begin{document}
\PrintDate
\end{document}
答案1
改进您的代码:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\int_new:N \mytest_date_day_int
\int_new:N \mytest_date_month_int
\int_new:N \mytest_date_year_int
\cs_new_protected:Npn \mytest_date_parse:n #1
{
\__mytest_date_parse:www #1 \q_stop
}
\cs_new_protected:Npn \__mytest_date_parse:www #1-#2-#3 \q_stop
{
\int_set:Nn \mytest_date_year_int {#1}
\int_set:Nn \mytest_date_month_int {#2}
\int_set:Nn \mytest_date_day_int {#3}
}
\keys_define:nn { my-test } {
date .code:n = { \mytest_date_parse:n { #1 } },
}
\NewDocumentCommand \Information { m } {
\keys_set:nn { my-test } { #1 }
}
\NewDocumentCommand \PrintDate { } {
Date:\nobreakspace
\int_use:N \mytest_date_day_int
\slash
\int_use:N \mytest_date_month_int
\slash
\int_use:N \mytest_date_year_int
}
\ExplSyntaxOff
\Information{
date = 2015-02-10,
}
\begin{document}
\PrintDate
\end{document}
最好将.code:n
位与实际实现分开。没有必要用六个参数定义解析器宏,因为三个参数是预先确定的。
不要忘记执行分配的函数应该是protected
。
这里检查日期是否为 ISO 格式:YYYY-MM-DD(但允许月份和年份为一位数字);这l3regex
是最简单的工具。如果日期无效,0/0/0
则会打印,但很容易添加合适的错误消息。
\documentclass{article}
\usepackage{xparse,l3regex}
\ExplSyntaxOn
\int_new:N \mytest_date_day_int
\int_new:N \mytest_date_month_int
\int_new:N \mytest_date_year_int
\cs_new_protected:Npn \mytest_date_parse:n #1
{
\regex_match:nnTF { \A \d{4}-\d{1,2}-\d{1,2} \Z } { #1 }
{
\__mytest_date_parse:www #1 \q_stop
}
{
\__mytest_date_parse:www 0000-00-00 \q_stop
}
}
\cs_new:Npn \__mytest_date_parse:www #1-#2-#3 \q_stop
{
\int_set:Nn \mytest_date_year_int {#1}
\int_set:Nn \mytest_date_month_int {#2}
\int_set:Nn \mytest_date_day_int {#3}
}
\keys_define:nn { my-test } {
date .code:n = { \mytest_date_parse:n {#1} },
}
\NewDocumentCommand \Information { m } {
\keys_set:nn { my-test } { #1 }
}
\NewDocumentCommand \PrintDate { } {
Date:\nobreakspace
\int_use:N \mytest_date_day_int
\slash
\int_use:N \mytest_date_month_int
\slash
\int_use:N \mytest_date_year_int
}
\ExplSyntaxOff
\Information{
date = 2015-02-10,
}
\begin{document}
\PrintDate
\Information{date=201-1-1}
\PrintDate
\Information{date=2015-1}
\PrintDate
\Information{date=2015/1/1}
\PrintDate
\end{document}
该正则表达式的意思是:整个字符串(\A
和\Z
代表开始和结束)应由四位数字(\d{4}
)、一个连字符、一到两位数字\d{1,2}
、一个连字符以及一到两位数字组成。任何其他格式都将返回 false。
另一个版本也接受date=20150101
,即一串八位数字,并将解析分为两种情况。
\documentclass{article}
\usepackage{xparse,l3regex}
\ExplSyntaxOn
\int_new:N \mytest_date_day_int
\int_new:N \mytest_date_month_int
\int_new:N \mytest_date_year_int
\cs_new_protected:Npn \mytest_date_validate_parse:n #1
{
\regex_match:nnTF { \A \d{4}-\d{1,2}-\d{1,2} \Z } { #1 }
{
\__mytest_date_parse:www #1 \q_stop
}
{
\regex_match:nnTF { \A \d{8} \Z } { #1 }
{
\__mytest_date_parse:nnnnnnnn #1
}
{
\__mytest_date_parse:nnnnnnnn 00000000
}
}
}
\cs_new:Npn \__mytest_date_parse:www #1-#2-#3 \q_stop
{
\int_set:Nn \mytest_date_year_int {#1}
\int_set:Nn \mytest_date_month_int {#2}
\int_set:Nn \mytest_date_day_int {#3}
}
\cs_new:Nn \__mytest_date_parse:nnnnnnnn
{
\int_set:Nn \mytest_date_year_int {#1#2#3#4}
\int_set:Nn \mytest_date_month_int {#5#6}
\int_set:Nn \mytest_date_day_int {#7#8}
}
\keys_define:nn { my-test } {
date .code:n = { \mytest_date_validate_parse:n {#1} },
}
\NewDocumentCommand \Information { m } {
\keys_set:nn { my-test } { #1 }
}
\NewDocumentCommand \PrintDate { } {
Date:\nobreakspace
\int_use:N \mytest_date_day_int
\slash
\int_use:N \mytest_date_month_int
\slash
\int_use:N \mytest_date_year_int
}
\ExplSyntaxOff
\Information{
date = 2015-02-10,
}
\begin{document}
Good: \PrintDate
\Information{date=201-1-1}%bad
Bad: \PrintDate
\Information{date=2015-1}%bad
Bad: \PrintDate
\Information{date=2015/1/1}%bad
Bad: \PrintDate
\Information{date=20150101}%good
Good: \PrintDate
\Information{date=201511}%bad
Bad: \PrintDate
\Information{date=201501012}%bad
Bad: \PrintDate
\end{document}
答案2
您可以使用解析器函数并在中引入夸克date .code:n
。请注意,夸克\q_stop
用于限定最后一个参数的长度。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\int_new:N \mytest_date_day_int
\int_new:N \mytest_date_month_int
\int_new:N \mytest_date_year_int
\cs_new:Npn \mytest_date_parse:wNNN #1-#2-#3 \q_stop #4 #5 #6
{
\int_set:Nn #4 {#1}
\int_set:Nn #5 {#2}
\int_set:Nn #6 {#3}
}
\keys_define:nn { my-test } {
date .code:n = {
\mytest_date_parse:wNNN
#1 \q_stop
\mytest_date_day_int
\mytest_date_month_int
\mytest_date_year_int
},
}
\NewDocumentCommand \Information { m } {
\keys_set:nn { my-test } { #1 }
}
\NewDocumentCommand \PrintDate { } {
Date:\nobreakspace
\int_use:N \mytest_date_day_int
\slash
\int_use:N \mytest_date_month_int
\slash
\int_use:N \mytest_date_year_int
}
\ExplSyntaxOff
\Information{
date = 2015-02-10,
}
\begin{document}
\PrintDate
\end{document}