texlive[63898] Master/texmf-dist: zhnumber (14jul22)

commits+karl at tug.org commits+karl at tug.org
Thu Jul 14 22:21:27 CEST 2022


Revision: 63898
          http://tug.org/svn/texlive?view=revision&revision=63898
Author:   karl
Date:     2022-07-14 22:21:27 +0200 (Thu, 14 Jul 2022)
Log Message:
-----------
zhnumber (14jul22)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/zhnumber/README.md
    trunk/Master/texmf-dist/doc/latex/zhnumber/zhnumber.pdf
    trunk/Master/texmf-dist/source/latex/zhnumber/zhnumber.dtx
    trunk/Master/texmf-dist/source/latex/zhnumber/zhnumber.ins
    trunk/Master/texmf-dist/tex/latex/zhnumber/zhnumber-big5.cfg
    trunk/Master/texmf-dist/tex/latex/zhnumber/zhnumber-gbk.cfg
    trunk/Master/texmf-dist/tex/latex/zhnumber/zhnumber-utf8.cfg
    trunk/Master/texmf-dist/tex/latex/zhnumber/zhnumber.sty

Modified: trunk/Master/texmf-dist/doc/latex/zhnumber/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/zhnumber/README.md	2022-07-14 20:21:15 UTC (rev 63897)
+++ trunk/Master/texmf-dist/doc/latex/zhnumber/README.md	2022-07-14 20:21:27 UTC (rev 63898)
@@ -38,7 +38,7 @@
 Copyright and Licence
 ---------------------
 
-    Copyright (C) 2012, 2014-2020 by Qing Lee <sobenlee at gmail.com>
+    Copyright (C) 2012, 2014-2020, 2022 by Qing Lee <sobenlee at gmail.com>
     ----------------------------------------------------------------------
 
     This work may be distributed and/or modified under the

Modified: trunk/Master/texmf-dist/doc/latex/zhnumber/zhnumber.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/source/latex/zhnumber/zhnumber.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/zhnumber/zhnumber.dtx	2022-07-14 20:21:15 UTC (rev 63897)
+++ trunk/Master/texmf-dist/source/latex/zhnumber/zhnumber.dtx	2022-07-14 20:21:27 UTC (rev 63898)
@@ -44,7 +44,7 @@
 Copyright and Licence
 ---------------------
 
-    Copyright (C) 2012, 2014-2020 by Qing Lee <sobenlee at gmail.com>
+    Copyright (C) 2012, 2014-2020, 2022 by Qing Lee <sobenlee at gmail.com>
     ----------------------------------------------------------------------
 
     This work may be distributed and/or modified under the
@@ -83,7 +83,7 @@
 
 \preamble
 
-    Copyright (C) 2012, 2014-2020 by Qing Lee <sobenlee at gmail.com>
+    Copyright (C) 2012, 2014-2020, 2022 by Qing Lee <sobenlee at gmail.com>
 --------------------------------------------------------------------------
 
     This work may be distributed and/or modified under the
@@ -141,7 +141,7 @@
 %</internal>
 %<package>\NeedsTeXFormat{LaTeX2e}
 %<package>\RequirePackage{expl3}
-%<+package|config>\GetIdInfo$Id: zhnumber.dtx c4664c6 2020-05-01 21:10:24 +0800 Qing Lee <sobenlee at gmail.com> $
+%<+package|config>\GetIdInfo$Id: zhnumber.dtx 5e8c3fe 2022-07-14 18:53:36 +0800 Qing Lee <sobenlee at gmail.com> $
 %<package>  {Typesetting numbers with Chinese glyphs}
 %<config&utf8>  {Chinese numerals with UTF8 encoding}
 %<config&big5>  {Chinese numerals with Big5 encoding}
@@ -150,9 +150,10 @@
 %<config&utf8>\ProvidesExplFile{\ExplFileName-utf8.cfg}
 %<config&big5>\ProvidesExplFile{\ExplFileName-big5.cfg}
 %<config&gbk>\ProvidesExplFile{\ExplFileName-gbk.cfg}
-%<package|config>  {\ExplFileDate}{2.8}{\ExplFileDescription}
+%<package|config>  {\ExplFileDate}{3.0}{\ExplFileDescription}
 %<*driver>
 \documentclass{ctxdoc}
+\SideBySideExampleSet{xrightmargin=.6\linewidth}
 \begin{document}
   \DocInput{\jobname.dtx}
   \IndexLayout
@@ -161,7 +162,7 @@
 %</driver>
 % \fi
 %
-% \CheckSum{1189}
+% \CheckSum{1394}
 % \GetFileId{zhnumber.sty}
 %
 % \title{\bfseries\pkg{zhnumber} 宏包}
@@ -181,22 +182,22 @@
 %
 % \section{使用方法}
 %
-% \begin{function}[updated=2014-09-09]{encoding}
+% \begin{function}[updated=2022-07-10]{encoding}
 %   \begin{syntax}
-%     encoding = <GBK|Big5|UTF8>
+%     encoding = <GBK|Big5|(UTF8)>
 %   \end{syntax}
 %   用于指定编码的宏包选项,可以在调用宏包的时候设定,也可以用 \tn{zhnumsetup}
 %   在导言区内设定。对于 \upLaTeX、\XeLaTeX{} 和 \LuaLaTeX,不用指定编码,宏包将
 %   自动使用 |UTF8| 编码。只有 \LaTeX{} 和 \pdfLaTeX{} 需要指定编码,如果没有指定,
-%   默认将使用 |GBK|。
+%   默认也使用 |UTF8|。
 % \end{function}
 %
-% \begin{function}[rEXP, updated=2014-09-12]{\zhnumber}
+% \begin{function}[EXP, updated=2022-07-10]{\zhnumber}
 %   \begin{syntax}
 %     \tn{zhnumber} \Arg{number}
 %   \end{syntax}
 %   以中文格式输出数字。这里的数字可以是整数、小数和分数。例如
-%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.6\linewidth,gobble=5]
+%   \begin{SideBySideExample}
 %     \zhnumber{2012020120}\\
 %     \zhnumber{2 012 020 120}\\
 %     \zhnumber{2,012,020,120}\\
@@ -210,7 +211,7 @@
 %   \end{SideBySideExample}
 % \end{function}
 %
-% \begin{function}[rEXP, updated=2014-09-09]{\zhdigits}
+% \begin{function}[EXP, updated=2022-07-10]{\zhdigits}
 %   \begin{syntax}
 %     \tn{zhdigits}   \Arg{number}
 %     \tn{zhdigits} * \Arg{number}
@@ -217,119 +218,119 @@
 %   \end{syntax}
 %   将阿拉伯数字转换为中文数字串。缺省状态下,\tn{zhdigits} 将 0 映射为〇,如果需要
 %   将其映射为零,可以使用带星号的形式。例如
-%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.6\linewidth,gobble=5]
+%   \begin{SideBySideExample}
 %     \zhdigits{2012020120}\\
 %     \zhdigits*{2012020120}
 %   \end{SideBySideExample}
 % \end{function}
 %
-% \begin{function}[rEXP, updated=2016-05-01]{\zhnum}
+% \begin{function}[EXP, updated=2022-07-10]{\zhnum}
 %   \begin{syntax}
 %     \tn{zhnum} \Arg{counter}
 %     \tn{pagenumbering} \{zhnum\}
 %   \end{syntax}
 %   与 |\roman| 等类似,用于将 \LaTeX 计数器的值转换为中文数字。例如
-%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.6\linewidth,gobble=5]
+%   \begin{SideBySideExample}
 %     \zhnum{section}
 %   \end{SideBySideExample}
 % \end{function}
 %
-% \begin{function}[rEXP, added=2016-05-01]{\zhdig}
+% \begin{function}[EXP, updated=2022-07-10]{\zhdig}
 %   \begin{syntax}
 %     \tn{zhdig} \Arg{counter}
 %     \tn{pagenumbering} \{zhdig\}
 %   \end{syntax}
 %   与 |\roman| 等类似,用于将 \LaTeX 计数器的值转换为中文数字串。例如
-%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.6\linewidth,gobble=5]
+%   \begin{SideBySideExample}
 %     \zhdig{section}
 %   \end{SideBySideExample}
 % \end{function}
 %
-% \begin{function}[rEXP, added=2012-05-25]{\zhweekday}
+% \begin{function}[EXP, updated=2022-07-10]{\zhweekday}
 %   \begin{syntax}
 %     \tn{zhweekday} \Arg{yyyy/mm/dd}
 %   \end{syntax}
 %   输出日期当天的星期。例如
-%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.6\linewidth,gobble=5]
+%   \begin{SideBySideExample}
 %     \zhweekday{2012/5/20}
 %   \end{SideBySideExample}
 % \end{function}
 %
-% \begin{function}[rEXP, added=2012-05-25]{\zhdate}
+% \begin{function}[EXP, updated=2022-07-10]{\zhdate}
 %   \begin{syntax}
 %     \tn{zhdate}   \Arg{yyyy/mm/dd}
 %     \tn{zhdate} * \Arg{yyyy/mm/dd}
 %   \end{syntax}
 %   以中文格式输出日期,其中带 |*| 的命令还输出星期。例如
-%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.6\linewidth,gobble=5]
+%   \begin{SideBySideExample}
 %     \zhdate{2012/5/21}\\
 %     \zhdate*{2012/5/21}
 %   \end{SideBySideExample}
 % \end{function}
 %
-% \begin{function}[rEXP, added=2012-05-25]{\zhtoday}
+% \begin{function}[EXP, updated=2022-07-10]{\zhtoday}
 %   与 |\today| 类似,以中文输出当天的日期。例如
-%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.6\linewidth,gobble=5]
+%   \begin{SideBySideExample}
 %     \zhtoday
 %   \end{SideBySideExample}
 % \end{function}
 %
-% \begin{function}[rEXP, added=2012-05-25]{\zhtime}
+% \begin{function}[EXP, updated=2022-07-10]{\zhtime}
 %   \begin{syntax}
 %     \tn{zhtime} \Arg{hh:mm}
 %   \end{syntax}
 %   以中文格式输出时间。例如
-%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.6\linewidth,gobble=5]
+%   \begin{SideBySideExample}
 %     \zhtime{23:56}
 %   \end{SideBySideExample}
 % \end{function}
 %
-% \begin{function}[rEXP, added=2012-05-25]{\zhcurrtime}
+% \begin{function}[EXP, updated=2022-07-10]{\zhcurrtime}
 %   输出当前的时间。例如
-%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.6\linewidth,gobble=5]
+%   \begin{SideBySideExample}
 %     \zhcurrtime
 %   \end{SideBySideExample}
 % \end{function}
 %
-% \begin{function}[rEXP, added=2015-05-20]{\zhtiangan}
+% \begin{function}[EXP, updated=2022-07-10]{\zhtiangan}
 %   \begin{syntax}
 %     \tn{zhtiangan} \Arg{number}
 %   \end{syntax}
 %   输出对应的天干计数。\meta{number} 的正常范围是 1--10,超出范围的数字将输出空值。例如
-%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.4\linewidth,gobble=5]
+%   \begin{SideBySideExample}[xrightmargin=.4\linewidth]
 %     \zhtiangan{1} \zhtiangan{2} \zhtiangan{3}
 %     \zhtiangan{4} \zhtiangan{5} \zhtiangan{10}
 %   \end{SideBySideExample}
 % \end{function}
 %
-% \begin{function}[rEXP, added=2015-05-20]{\zhdizhi}
+% \begin{function}[EXP, updated=2022-07-10]{\zhdizhi}
 %   \begin{syntax}
 %     \tn{zhdizhi} \Arg{number}
 %   \end{syntax}
 %   输出对应的地支计数。\meta{number} 的正常范围是 1--12,超出范围的数字将输出空值。例如
-%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.4\linewidth,gobble=5]
+%   \begin{SideBySideExample}[xrightmargin=.4\linewidth]
 %     \zhdizhi{1} \zhdizhi{2} \zhdizhi{3}
 %     \zhdizhi{4} \zhdizhi{5} \zhdizhi{12}
 %   \end{SideBySideExample}
 % \end{function}
 %
-% \begin{function}[rEXP, added=2015-05-20]{\zhganzhi}
+% \begin{function}[EXP, updated=2022-07-10]{\zhganzhi}
 %   \begin{syntax}
 %     \tn{zhganzhi} \Arg{number}
 %   \end{syntax}
 %   输出对应的干支计数。\meta{number} 的正常范围是 1--60,超出范围的数字将输出空值。例如
-%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.4\linewidth,gobble=5]
+%   \begin{SideBySideExample}[xrightmargin=.4\linewidth]
 %     \zhganzhi{1} \zhganzhi{2} \zhganzhi{3} \\
 %     \zhganzhi{4} \zhganzhi{5} \zhganzhi{60}
 %   \end{SideBySideExample}
 % \end{function}
 %
-% \begin{function}[rEXP, added=2015-05-20]{\zhganzhinian}
+% \begin{function}[EXP, updated=2022-07-10]{\zhganzhinian}
 %   \begin{syntax}
 %     \tn{zhganzhinian} \Arg{year}
 %   \end{syntax}
 %   输出公元纪年 \meta{year} 对应的干支纪年。公元前的年份用负数表示。例如
-%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.4\linewidth,gobble=5]
+%   \begin{SideBySideExample}[xrightmargin=.4\linewidth]
 %     \zhganzhinian{1898}  \zhganzhinian{-246} \\
 %     \zhganzhinian{-2697} \zhganzhinian{\year}
 %   \end{SideBySideExample}
@@ -345,7 +346,7 @@
 %   数字大于 $10^{4(n+12)}-1$ 时,统一用 \meta{character} 设置输出数字的进位。
 % \end{function}
 %
-% \begin{function}{\zhnumsetup}
+% \begin{function}[updated=2022-07-10]{\zhnumsetup}
 %   \begin{syntax}
 %     \tn{zhnumsetup} \{<key_1>=<val_1>, <key_2>=<val_2>, ...\}
 %   \end{syntax}
@@ -359,7 +360,7 @@
 %   \end{syntax}
 %   设置日期和时间的数字格式,\meta{Arabic} 为阿拉伯数字,而 \meta{Chinese} 为中文数字。
 %   例如
-%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.6\linewidth,gobble=5]
+%   \begin{SideBySideExample}
 %     \zhnumsetup{time=Chinese}
 %     \zhtoday\zhcurrtime
 %   \end{SideBySideExample}
@@ -387,8 +388,8 @@
 %     \item[Ancient] 以廿输出 20,以卅输出 30,以卌输出 40,以皕输出 200。
 %   \end{description}
 %
-%   可以设置 |style| 为其中一个,也可以是前三个与后两个的适当组合,默认是简体小写。例如
-%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.4\linewidth,gobble=5]
+%   可以设置 |style| 为其中一个,也可以是前两个与后三个的适当组合,默认是简体小写。例如
+%   \begin{SideBySideExample}[xrightmargin=.4\linewidth]
 %     \zhnumsetup{style={Traditional,Financial}}
 %     \zhnumber{62012.3}\\
 %     \zhnumsetup{style=Ancient}
@@ -411,7 +412,7 @@
 %   天干、地支和干支的数字都有一定范围。若参数大于这个范围,\tn{tiangan} 等将输出空值。
 %   可以将本选项设置为 |true|,对超出范围的数字取相应的模。
 %   请注意,数字 |0| 的结果总是为空值。例如
-%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.3\linewidth,gobble=5]
+%   \begin{SideBySideExample}[xrightmargin=.3\linewidth]
 %     \zhnumsetup{ganzhi-cyclic}
 %     \zhtiangan{11} \zhtiangan{12} \zhtiangan{209}
 %     \zhtiangan{-1} \zhtiangan{-2} \zhtiangan{-683} \\
@@ -422,9 +423,8 @@
 %   \end{SideBySideExample}
 % \end{function}
 %
-%\bigskip
 % \pkg{zhnumber} 提供下列选项来控制阿拉伯数字的中文映射。
-% \begin{verbatim}[frame=single]
+% \begin{frameverb}
 %   - -0 0 1 2 3 4 5 6 7 8 9 10 20 30 40 100 200 1000
 %   E2 E3 E4 E8 E12 E16 E20 E24 E28 E32 E36 E40 E44
 %   F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F100 F1000 FE2 FE3
@@ -433,18 +433,18 @@
 %   GZ1 GZ2 GZ3 GZ4 GZ5 GZ6 GZ7 GZ8 GZ9 GZ10 ... GZ60
 %   dot and parts
 %   year month day hour minute weekday mon tue wed thu fri sat sun
-% \end{verbatim}
+% \end{frameverb}
 % 其中 |-| 设置负,|-0| 设置〇,|dot| 设置小数的点,|and| 和 |parts| 分别设置分数
 % 的“又”和“分之”,|E|$n$ 设置 $10^n$,|F|$n$ 设置数字 $n$ 的大写,|T|$n$ 设置
 % 数字 $n$ 的天干,|D|$n$ 设置数字 $n$ 的地支,而 |GZ|$n$ 设置数字 $n$ 的干支。
 % 其他的选项同字面意思,不再赘述。例如
-% \begin{verbatim}[frame=single]
+% \begin{frameverb}
 %   \zhnumsetup{2={两}}
-% \end{verbatim}
+% \end{frameverb}
 % 可以将 2 映射成两。需要说明的是,\pkg{zhnumber} 将优先使用这里的设置,所以可能会影响
 % 到 |style| 选项。如果要恢复 |style| 的功能,可以使用 |reset| 选项。
 %
-% \begin{function}[updated=2014-09-12]{reset}
+% \begin{function}[updated=2022-07-10]{reset}
 %   \begin{syntax}
 %     reset
 %   \end{syntax}
@@ -463,7 +463,7 @@
 %   才会有效果。
 % \end{function}
 %
-% \begin{function}[updated=2016-05-01]{\zhnumber,\zhdigits,\zhnum,\zhdig}
+% \begin{function}[updated=2022-07-10]{\zhnumber,\zhdigits,\zhnum,\zhdig}
 %   \begin{syntax}
 %     \tn{zhnumber}   \oarg{options} \Arg{number}
 %     \tn{zhdigits} * \oarg{options} \Arg{number}
@@ -504,16 +504,65 @@
 %    \end{macrocode}
 %
 %    \begin{macrocode}
-\RequirePackage { xparse , l3keys2e }
+\cs_if_exist:NF \NewDocumentCommand
+  { \RequirePackage { xparse } }
 %    \end{macrocode}
 %
+% \begin{macro}{\zhnum_output:n,\zhnum_expand_wrap:wn}
+% 受益于 \tn{tex_expanded:D},我们使用如下的结构简单实现 |f| 展开。
+% \begin{verbatim}
+%   \exp_not:e
+%     {
+%       ...
+%       \exp_not:o { <tl_var> }
+%       ...
+%       \exp_not:o { <tl_var> }
+%       ...
+%       \exp_not:o { <tl_var> }
+%       ...
+%     }
+% \end{verbatim}
+% 并且可以将 \tn{zhnumber} 等无风险地使用于诸如 \tn{edef} 定义等完全展开的场合。
+% 从 \TeXLive\ 2019 开始,各个主要引擎都已经支持 \tn{tex_expanded:D},
+% 对于较早的版本,\LaTeXiii\ 也实现了一个模拟。
+%    \begin{macrocode}
+\cs_new:Npn \zhnum_output:n #1
+  { \exp_args:Nc \zhnum_exp_not:o { l_@@_ #1 _tl } }
+\cs_new_protected:Npn \zhnum_expand_wrap:wn #1#
+  { \@@_expand_wrap_aux:nn {#1} }
+\cs_new_protected:Npn \@@_expand_wrap_aux:nn #1#2
+  { #1 { \exp_not:e {#2} } }
+\cs_new_eq:NN \zhnum_exp_not:e \exp_not:e
+\cs_new_eq:NN \zhnum_exp_not:o \exp_not:o
+%    \end{macrocode}
+% 但这种方式也有一定的缺点,比如在 \pdfTeX\ 引擎下,\pkg{hyperref} 包的
+% \tn{pdfstringdef} 就需要把汉字首字节的活动字符展开,
+% 并作适当的重定义后才能得到预期的结果。为此,我们定义一个清除命令,不使用以上机制。
+%    \begin{macrocode}
+\cs_new_protected:Npn \zhnumClearWrapper
+  {
+    \cs_set_eq:NN \zhnum_exp_not:e \use:n
+    \cs_set_eq:NN \zhnum_exp_not:o \use:n
+  }
+\cs_new_protected:Npn \zhnumResetWrapper
+  {
+    \cs_set_eq:NN \zhnum_exp_not:e \exp_not:e
+    \cs_set_eq:NN \zhnum_exp_not:o \exp_not:o
+  }
+\hook_gput_code:nnn { package/CJKutf8/after } { zhnumber }
+  { \g at addto@macro \pdfstringdefPreHook { \zhnumClearWrapper } }
+\hook_gput_code:nnn { package/xCJK2uni/after } { zhnumber }
+  { \g at addto@macro \pdfstringdefPreHook { \zhnumClearWrapper } }
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}{\zhnumber}
 % 用于将输入的数字按照中文格式输出。
 %    \begin{macrocode}
-\DeclareExpandableDocumentCommand \zhnumber { +o +m }
+\NewExpandableDocumentCommand \zhnumber { +o +m }
   {
-    \IfNoValueTF {#1}
-      { \zhnum_number:f }
+    \tl_if_novalue:nTF {#1}
+      { \zhnum_number:e }
       { \zhnumberwithoptions {#1} }
     {#2}
   }
@@ -526,8 +575,8 @@
  \NewDocumentCommand \zhnumberwithoptions { +m +m }
   {
     \group_begin:
-      \keys_set:nn { zhnum / options } {#1}
-      \zhnum_number:f {#2}
+      \zhnum_set:n {#1}
+      \zhnum_number:e {#2}
     \group_end:
   }
 %    \end{macrocode}
@@ -537,6 +586,7 @@
 % \begin{macro}{\@@_number:www}
 % 先判断输入的是小数还是分数。
 %    \begin{macrocode}
+\zhnum_expand_wrap:wn
 \cs_new:Npn \zhnum_number:n #1
   { \@@_number:www #1 . \q_nil . \q_stop }
 \cs_new:Npn \@@_number:www #1 . #2 . #3 \q_stop
@@ -545,7 +595,7 @@
       { \@@_integer_or_fraction:www #1 / \q_nil / \q_stop }
       { \zhnum_decimal:nn {#1} {#2} }
   }
-\cs_generate_variant:Nn \zhnum_number:n { f }
+\cs_generate_variant:Nn \zhnum_number:n { e }
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
@@ -570,7 +620,7 @@
     \quark_if_nil:nTF {#3}
       {
         \zhnum_blank_to_zero:n {#1}
-        \c_@@_parts_tl
+        \zhnum_output:n { parts }
         \zhnum_blank_to_zero:n {#2}
       }
       {
@@ -577,10 +627,10 @@
         \tl_if_blank:nF {#2}
           {
             \zhnum_number:n {#2}
-            \c_@@_and_tl
+            \zhnum_output:n { and }
           }
         \zhnum_blank_to_zero:n {#1}
-        \c_@@_parts_tl
+        \zhnum_output:n { parts }
         \zhnum_blank_to_zero:n {#3}
       }
   }
@@ -592,9 +642,10 @@
 %    \begin{macrocode}
 \cs_new:Npn \zhnum_decimal:nn #1#2
   {
-    \zhnum_blank_to_zero:n {#1} \c_@@_dot_tl
+    \zhnum_blank_to_zero:n {#1}
+    \zhnum_output:n { dot }
     \tl_if_blank:nTF {#2}
-      { \c_@@_zero_tl }
+      { \zhnum_output:n { 0 } }
       { \zhnum_digits_zero:n {#2} }
   }
 %    \end{macrocode}
@@ -606,7 +657,7 @@
 \cs_new:Npn \zhnum_blank_to_zero:n #1
   {
     \tl_if_blank:nTF {#1}
-      { \c_@@_zero_tl }
+      { \zhnum_output:n { 0 } }
       { \zhnum_number:n {#1} }
   }
 %    \end{macrocode}
@@ -615,9 +666,9 @@
 % \begin{macro}{\zhnum,\zhnumberwithoptions}
 % 用于将 \LaTeX{} 计数器按中文格式输出。
 %    \begin{macrocode}
-\DeclareExpandableDocumentCommand \zhnum { +o +m }
+\NewExpandableDocumentCommand \zhnum { +o +m }
   {
-    \IfNoValueTF {#1}
+    \tl_if_novalue:nTF {#1}
       { \zhnum_counter:n }
       { \zhnumwithoptions {#1} }
     {#2}
@@ -625,7 +676,7 @@
 \NewDocumentCommand \zhnumwithoptions { +m +m }
   {
     \group_begin:
-      \keys_set:nn { zhnum / options } {#1}
+      \zhnum_set:n {#1}
       \zhnum_counter:n {#2}
     \group_end:
   }
@@ -645,6 +696,7 @@
   { \msg_expandable_error:nnn { zhnumber } { not-counter } {#1} }
 \msg_new:nnn  { zhnumber } { not-counter }
   { `#1'~is~not~a~LaTeX~counter. }
+\zhnum_expand_wrap:wn
 \cs_new:Npn \zhnum_int:n #1
   {
     \int_compare:nNnTF {#1} > \c_zero_int
@@ -652,10 +704,10 @@
       {
         \int_compare:nNnTF {#1} < \c_zero_int
           {
-            \c_@@_minus_tl
+            \zhnum_output:n { minus }
             \zhnum_parse_number:f { \int_eval:n { - #1 } }
           }
-          { \c_@@_zero_tl }
+          { \zhnum_output:n { 0 } }
       }
   }
 %    \end{macrocode}
@@ -735,10 +787,10 @@
 \cs_new:Npn \@@_read_integer:www #1 ; #2 ; #3 ;
   {
     \int_compare:nNnTF {#2} = \c_zero_int
-      { \c_@@_zero_tl }
+      { \zhnum_output:n { 0 } }
       {
         \int_compare:nNnF {#1} = \c_one_int
-          { \c_@@_minus_tl }
+          { \zhnum_output:n { minus } }
         \zhnum_parse_number:nn {#2} {#3}
       }
   }
@@ -772,7 +824,7 @@
 \cs_new:Npn \@@_parse_number:nnn #1#2
   {
     \int_compare:nNnTF {#2} < 2
-      { \zhnum_digit_map:n }
+      { \zhnum_output:n }
       {
         \int_compare:nNnTF {#1} = \c_zero_int
           { \zhnum_split_number:fn { \int_eval:n { #2 / 4 - 1 } } }
@@ -823,7 +875,7 @@
     \int_compare:nNnTF { #4#5#6#7 } = \c_zero_int
       { \use_i:nn }
       {
-        \bool_if:NF #1 { \c_@@_zero_tl }
+        \bool_if:NF #1 { \zhnum_output:n { 0 } }
         \zhnum_process_number:NNNNNN #4#5#6#7#1#2
         \zhnum_scale_map:n {#3}
         \int_compare:nNnTF {#7} = \c_zero_int
@@ -842,21 +894,34 @@
 \cs_new:Npn \zhnum_process_number:NNNNNN #1#2#3#4#5#6
   {
     \int_compare:nNnTF {#1} = \c_zero_int
-      { \bool_if:NF #6 { \c_@@_zero_tl } }
-      { \zhnum_digit_map:n {#1} \c_@@_thousand_tl }
+      {
+        \bool_if:NF #6
+          { \zhnum_output:n { 0 } }
+      }
+      {
+        \zhnum_output:n {#1}
+        \zhnum_output:n { 1000 }
+      }
     \int_compare:nNnTF {#2} = \c_zero_int
-      { \int_compare:nNnF { #1 * (#3#4) } = \c_zero_int { \c_@@_zero_tl } }
       {
-        \bool_lazy_and:nnTF
-          { \l_@@_ancient_bool }
-          { \int_compare_p:nNn {#2} = 2 }
-          { \zhnum_digit_map:n { #2 00 } }
-          { \zhnum_digit_map:n {#2} \c_@@_hundred_tl }
+        \int_compare:nNnF { #1 * (#3#4) } = \c_zero_int
+          { \zhnum_output:n { 0 } }
       }
+      {
+        \int_compare:nNnTF {#2} = 2
+          { \zhnum_output:n { 200 } }
+          {
+            \zhnum_output:n {#2}
+            \zhnum_output:n { 100 }
+          }
+      }
     \int_compare:nNnTF {#3} = \c_zero_int
-      { \int_compare:nNnF { #2 * #4 } = \c_zero_int { \c_@@_zero_tl } }
       {
-        \bool_lazy_all:nF
+        \int_compare:nNnF { #2 * #4 } = \c_zero_int
+          { \zhnum_output:n { 0 } }
+      }
+      {
+        \bool_lazy_all:nTF
           {
             { \int_compare_p:nNn {#3}   = \c_one_int }
             { \int_compare_p:nNn {#1#2} = \c_zero_int }
@@ -863,16 +928,18 @@
             {#6}
             {#5}
           }
+          { \zhnum_output:n { 10 } }
           {
-            \bool_lazy_and:nnTF
-              { \l_@@_ancient_bool }
-              { \int_compare_p:n { 1 < #3 < 5 } }
-              { \zhnum_digit_map:n { #3 0 } \use_none:n }
-              { \zhnum_digit_map:n {#3} }
+            \int_compare:nTF { 1 < #3 < 5 }
+              { \zhnum_output:n { #3 0 } }
+              {
+                \zhnum_output:n {#3}
+                \zhnum_output:n { 10 }
+              }
           }
-        \c_@@_ten_tl
       }
-    \int_compare:nNnF {#4} = \c_zero_int { \zhnum_digit_map:n {#4} }
+    \int_compare:nNnF {#4} = \c_zero_int
+      { \zhnum_output:n {#4} }
   }
 %    \end{macrocode}
 % \end{macro}
@@ -880,9 +947,9 @@
 % \begin{macro}{\zhdig}
 % 用于将 \LaTeX{} 计数器按中文数字串输出。
 %    \begin{macrocode}
-\DeclareExpandableDocumentCommand \zhdig { +o +m }
+\NewExpandableDocumentCommand \zhdig { +o +m }
   {
-    \IfNoValueTF {#1}
+    \tl_if_novalue:nTF {#1}
       { \zhnum_digits_counter:n }
       { \zhdigwithoptions {#1} }
     {#2}
@@ -890,7 +957,7 @@
 \NewDocumentCommand \zhdigwithoptions { +m +m }
   {
     \group_begin:
-      \keys_set:nn { zhnum / options } {#1}
+      \zhnum_set:n {#1}
       \zhnum_digits_counter:n #1 {#2}
     \group_end:
   }
@@ -906,7 +973,8 @@
 % \begin{macro}[int]{\@zhdig}
 % 用于支持 |\pagenumbering{zhdig}|。
 %    \begin{macrocode}
-\cs_new:Npn \@zhdig #1 { \zhnum_digits_null:f { \int_eval:n {#1} } }
+\cs_new:Npn \@zhdig #1
+  { \zhnum_digits_null:f { \int_eval:n {#1} } }
 %    \end{macrocode}
 % \end{macro}
 %
@@ -913,10 +981,10 @@
 % \begin{macro}{\zhdigits,\zhdigitswithoptions}
 % 将输入的数字输出为中文数字串输出。
 %    \begin{macrocode}
-\DeclareExpandableDocumentCommand \zhdigits { +s +o +m }
+\NewExpandableDocumentCommand \zhdigits { +s +o +m }
   {
-    \IfNoValueTF {#2}
-      { \zhnum_digits:Nn #1 }
+    \tl_if_novalue:nTF {#2}
+      { \zhnum_digits:Ne #1 }
       { \zhdigitswithoptions {#1} {#2} }
     {#3}
   }
@@ -923,8 +991,8 @@
 \NewDocumentCommand \zhdigitswithoptions { +m +m +m }
   {
     \group_begin:
-      \keys_set:nn { zhnum / options } {#2}
-      \zhnum_digits:Nn #1 {#3}
+      \zhnum_set:n {#2}
+      \zhnum_digits:Ne #1 {#3}
     \group_end:
   }
 %    \end{macrocode}
@@ -934,10 +1002,10 @@
 % 快捷方式。
 %    \begin{macrocode}
 \cs_new:Npn \zhnum_digits_zero:n
-  { \zhnum_digits:Nn \BooleanTrue }
+  { \zhnum_digits:Nn \c_true_bool }
 \cs_new:Npn \zhnum_digits_null:n
-  { \zhnum_digits:Nn \BooleanFalse }
-\cs_generate_variant:Nn \zhnum_digits_null:n { V , v , f }
+  { \zhnum_digits:Nn \c_false_bool }
+\cs_generate_variant:Nn \zhnum_digits_null:n { v , f }
 %    \end{macrocode}
 % \end{macro}
 %
@@ -944,6 +1012,7 @@
 % \begin{macro}[int]{\zhnum_digits:Nn}
 % 与 \cs{zhnum_integer:n} 类似,但不用去掉多余的零。
 %    \begin{macrocode}
+\zhnum_expand_wrap:wn
 \cs_new:Npn \zhnum_digits:Nn #1#2
   {
     \exp_after:wN \@@_read_digits:w
@@ -970,7 +1039,8 @@
       { \@@_output_digits:NN #1#2 }
       {
         \quark_if_recursion_tail_stop:N #2
-        \if:w .\exp_not:N #2 \exp_after:wN \c_@@_dot_tl \fi:
+        \token_if_eq_charcode:NNT #2 .
+          { \zhnum_output:n { dot } }
       }
     \exp_after:wN \@@_read_digits_loop:NN \exp_after:wN #1
       \exp:w \exp_end_continue_f:w \use:n
@@ -978,20 +1048,20 @@
 \cs_new:Npn \@@_read_digits:w #1 ;
   {
     \int_compare:nNnF {#1} = \c_one_int
-      { \c_@@_minus_tl }
+      { \zhnum_output:n { minus } }
   }
 \cs_new:Npn \@@_output_digits:NN #1#2
   {
-    \cs:w
-      c_@@_
+    \zhnum_output:n
+      {
         \if_int_compare:w #2 = \c_zero_int
-          \IfBooleanTF #1 { zero } { null }
+          \bool_if:NTF #1 { zero } { null }
         \else:
           #2
         \fi:
-      _tl
-    \cs_end:
+      }
   }
+\cs_generate_variant:Nn \zhnum_digits:Nn { Ne }
 %    \end{macrocode}
 % \end{macro}
 %
@@ -998,11 +1068,10 @@
 % \begin{macro}{\zhdate}
 % 输出中文日期。
 %    \begin{macrocode}
-\DeclareExpandableDocumentCommand \zhdate { +s +m }
+\NewExpandableDocumentCommand \zhdate { +s +m }
   {
     \@@_date:www #2 \q_stop
-    \IfBooleanT #1
-      { \@@_week_day:www #2 \q_stop }
+    \bool_if:NT #1 { \@@_week_day:www #2 \q_stop }
   }
 \cs_new:Npn \@@_date:www #1/#2/#3 \q_stop
   { \@@_date_aux:nnn {#1} {#2} {#3} }
@@ -1013,7 +1082,12 @@
 % 输出当天日期。
 %    \begin{macrocode}
 \cs_new:Npn \zhtoday
-  { \@@_date_aux:Vnn \tex_year:D \tex_month:D \tex_day:D }
+  {
+    \@@_date_aux:nnn
+      { \int_value:w \tex_year:D }
+      { \tex_month:D }
+      { \tex_day:D }
+  }
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1025,15 +1099,15 @@
       { \@@_date_aux:NNnnnn \zhnum_digits_null:n \zhnum_int:n { } }
       { \@@_date_aux:Nnnnn \int_to_arabic:n { \l_@@_arabic_sep_tl } }
   }
-\cs_new:Npn \@@_date_aux:Nnnnn #1
-  { \@@_date_aux:NNnnnn #1#1 }
+\cs_new:Npn \@@_date_aux:Nnnnn #1#2
+  { \@@_date_aux:NNnnnn #1#1 { \zhnum_exp_not:o {#2} } }
+\zhnum_expand_wrap:wn
 \cs_new:Npn \@@_date_aux:NNnnnn #1#2#3#4#5#6
   {
-    #1 {#4} #3 \c_@@_year_tl  #3
-    #2 {#5} #3 \c_@@_month_tl #3
-    #2 {#6} #3 \c_@@_day_tl
+    #1 {#4} #3 \zhnum_output:n { year }  #3
+    #2 {#5} #3 \zhnum_output:n { month } #3
+    #2 {#6} #3 \zhnum_output:n { day }
   }
-\cs_generate_variant:Nn \@@_date_aux:nnn { V }
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1048,16 +1122,17 @@
 % \begin{macro}{\@@_week_day:www}
 % 用 Zeller 公式计算的结果 $h$ 与实际星期的关系是 $d=h+5\pmod7+1$。
 %    \begin{macrocode}
+\zhnum_expand_wrap:wn
 \cs_new:Npn \@@_week_day:www #1/#2/#3 \q_stop
   {
     \if_case:w \zhnum_Zeller:nnn {#1} {#2} {#3} \exp_stop_f:
-           \c_@@_sat_tl
-      \or: \c_@@_sun_tl
-      \or: \c_@@_mon_tl
-      \or: \c_@@_tue_tl
-      \or: \c_@@_wed_tl
-      \or: \c_@@_thu_tl
-      \or: \c_@@_fri_tl
+           \zhnum_output:n { sat }
+      \or: \zhnum_output:n { sun }
+      \or: \zhnum_output:n { mon }
+      \or: \zhnum_output:n { tue }
+      \or: \zhnum_output:n { wed }
+      \or: \zhnum_output:n { thu }
+      \or: \zhnum_output:n { fri }
     \fi:
   }
 %    \end{macrocode}
@@ -1139,11 +1214,13 @@
 % \begin{macro}{\zhtime}
 % 输出时间。
 %    \begin{macrocode}
+\zhnum_expand_wrap:wn
 \cs_new:Npn \zhtime #1
   { \@@_time:ww #1 \q_stop }
-\use:x
+\use:e
   {
-    \cs_new:Npn \exp_not:N \@@_time:ww ##1 \c_colon_str ##2 \exp_not:N \q_stop
+    \cs_new:Npn \exp_not:N \@@_time:ww
+      #1 \c_colon_str #2 \exp_not:N \q_stop
   }
   { \@@_time_aux:nn {#1} {#2} }
 %    \end{macrocode}
@@ -1152,6 +1229,7 @@
 % \begin{macro}{\zhcurrtime}
 % 输出当前时间。
 %    \begin{macrocode}
+\zhnum_expand_wrap:wn
 \cs_new:Npn \zhcurrtime
   {
     \@@_time_aux:nn
@@ -1171,26 +1249,19 @@
   }
 \cs_new:Npn \@@_time_aux:Nnnn #1#2#3#4
   {
-    #1 {#3} #2 \c_@@_hour_tl #2
-    #1 {#4} #2 \c_@@_minute_tl
+    #1 {#3} #2 \zhnum_output:n { hour } #2
+    #1 {#4} #2 \zhnum_output:n { minute }
   }
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[int]{\zhnum_digit_map:n}
-% 阿拉伯数字与中文数字的映射。
-%    \begin{macrocode}
-\cs_new:Npn \zhnum_digit_map:n #1
-  { \use:c { c_@@_ #1 _tl } }
-%    \end{macrocode}
-% \end{macro}
-%
 % \begin{macro}[int]{\zhnum_scale_map:n,\zhnum_scale_map_loop:n}
 % 大数系统的映射。
 %    \begin{macrocode}
 \cs_new:Npn \zhnum_scale_map:n #1
   {
-    \cs_if_exist_use:cF { c_@@_s #1 _tl }
+    \tl_if_exist:cTF { l_@@_s #1 _tl }
+      { \zhnum_output:n { s #1 } }
       { \zhnum_scale_map_hook:n {#1} }
   }
 \cs_new:Npn \zhnum_scale_map_loop:n #1
@@ -1199,7 +1270,7 @@
 \int_new:N \l_@@_scale_int
 \int_set:Nn \l_@@_scale_int { 11 }
 \cs_new_eq:NN \zhnum_scale_map_hook:n \zhnum_scale_map_loop:n
-\tl_const:cn { c_@@_s0_tl } { }
+\tl_new:c { l_@@_s 0 _tl }
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1208,9 +1279,9 @@
 %    \begin{macrocode}
 \NewDocumentCommand \zhnumExtendScaleMap { > { \TrimSpaces } +o +m }
   {
-    \int_zero:N \l_tmpa_int
+    \int_zero:N \l_@@_tmp_int
     \clist_map_function:nN {#2} \zhnum_set_scale:n
-    \IfNoValueF {#1}
+    \tl_if_novalue:nF {#1}
       { \cs_set:Npn \zhnum_scale_map_hook:n ##1 {#1} }
   }
 %    \end{macrocode}
@@ -1220,13 +1291,21 @@
 %    \begin{macrocode}
 \cs_new_protected:Npn \zhnum_set_scale:n #1
   {
-    \int_incr:N \l_tmpa_int
-    \tl_set:Nx \l_tmpa_tl
-      { c_@@_s \int_eval:n { \l_tmpa_int + 11 } _tl }
-    \tl_if_exist:cF { \l_tmpa_tl }
-      { \int_incr:N \l_@@_scale_int }
-    \tl_set:cn { \l_tmpa_tl } {#1}
+    \int_incr:N \l_@@_tmp_int
+    \exp_args:Nc \@@_set_scale:Nn
+      { l_@@_s \int_eval:n { \l_@@_tmp_int + 11 } _tl }
+      {#1}
   }
+\cs_new_protected:Npn \@@_set_scale:Nn #1
+  {
+    \tl_if_exist:NF #1
+      {
+        \tl_new:N #1
+        \int_incr:N \l_@@_scale_int
+      }
+    \tl_set:Nn #1
+  }
+\int_new:N \l_@@_tmp_int
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1233,10 +1312,14 @@
 % \begin{macro}[int]{\zhnum_ganzhi_normal:nnn}
 % 保证干支的参数为正数。
 %    \begin{macrocode}
+\zhnum_expand_wrap:wn
 \cs_new:Npn \zhnum_ganzhi_normal:nnn #1#2#3
   {
     \int_compare:nNnF {#1} < \c_one_int
-      { \cs_if_exist_use:c { c_@@_ #2 _ #1 _tl } }
+      {
+        \cs_if_free:cF { l_@@_ #2 _ #1 _tl }
+          { \zhnum_output:n { #2 _ #1 } }
+      }
   }
 %    \end{macrocode}
 % \end{macro}
@@ -1245,11 +1328,13 @@
 % \begin{macro}{\@@_ganzhi_cyclic_mod:nnnn}
 % 对超出范围的数字取模,参数 |0| 的结果是空值。
 %    \begin{macrocode}
+\zhnum_expand_wrap:wn
 \cs_new:Npn \zhnum_ganzhi_cyclic:nnn #1#2#3
   {
     \int_compare:nNnF {#1} = \c_zero_int
       {
-        \cs_if_exist_use:cF { c_@@_ #2 _ #1 _tl }
+        \tl_if_exist:cTF { l_@@_ #2 _ #1 _tl }
+          { \zhnum_output:n { #2 _ #1 } }
           {
             \@@_ganzhi_cyclic_mod:fnnn
               { \int_mod:nn {#1} {#3} } {#1} {#2} {#3}
@@ -1259,11 +1344,11 @@
 \cs_new:Npn \@@_ganzhi_cyclic_mod:nnnn #1#2#3#4
   {
     \int_compare:nNnTF {#2} > \c_zero_int
-      { \use:c { c_@@_ #3 _ #1 _tl } }
+      { \zhnum_output:n { #3 _ #1 } }
       {
         \int_compare:nNnTF {#1} = \c_zero_int
-          { \use:c { c_@@_ #3 _ 1 _tl } }
-          { \use:c { c_@@_ #3 _ \int_eval:n {  #1 + #4 + 1 } _tl } }
+          { \zhnum_output:n { #3 _ 1 } }
+          { \zhnum_output:n { #3 _ \int_eval:n {  #1 + #4 + 1 } } }
       }
   }
 \cs_generate_variant:Nn \@@_ganzhi_cyclic_mod:nnnn { f }
@@ -1314,18 +1399,18 @@
 % \begin{macro}[int]{\zhnum_ganzhi_nian:n}
 % 干支纪年。公元元年是 |\zhganzhi{58}|。
 %    \begin{macrocode}
+\zhnum_expand_wrap:wn
 \cs_new:Npn \zhnum_ganzhi_nian:n #1
   {
     \int_compare:nNnTF {#1} > \c_zero_int
-      { \use:c { c_@@_ganzhi_ \int_mod:nn { #1 + 57 } { 60 } _tl } }
+      { \zhnum_output:n { ganzhi_ \int_mod:nn { #1 + 57 } { 60 } } }
       {
         \int_compare:nNnF {#1} = \c_zero_int
           {
-            \use:c
+            \zhnum_output:n
               {
-                c_@@_ganzhi_
-                  \int_eval:n { \int_mod:nn { #1 - 2 } { 60 } + 60 }
-                _tl
+                ganzhi_ \int_eval:n
+                  { \int_mod:nn { #1 - 2 } { 60 } + 60 }
               }
           }
       }
@@ -1336,67 +1421,101 @@
 %
 % 根据需要设置中文阿拉伯数字。
 %    \begin{macrocode}
+\tl_new:N \l_@@_kv_tl
+\tl_new:N \l_@@_tmp_tl
 \group_begin:
-  \tl_set:Nn \l_tmpa_tl
-    {
-      -   .tl_set:N = \l_@@_minus_tl ,
-      -0  .tl_set:N = \l_@@_null_tl ,
-    }
-  \tl_put_right:Nx \l_tmpa_tl
-    {
-      E2  .tl_set:N = \exp_not:c { l_@@_ 100 _tl } ,
-      E3  .tl_set:N = \exp_not:c { l_@@_ 1000 _tl } ,
-      FE2 .tl_set:N = \exp_not:c { l_@@_financial_ 100 _tl } ,
-      FE3 .tl_set:N = \exp_not:c { l_@@_financial_ 1000 _tl } ,
-      D11 .tl_set:N = \exp_not:c { l_@@_dizhi_ 11 _tl } ,
-      D12 .tl_set:N = \exp_not:c { l_@@_dizhi_ 12 _tl } ,
-      E44 .tl_set:N = \exp_not:c { l_@@_ s11 _tl } ,
-    }
+  \tl_build_begin:N \l_@@_kv_tl
   \int_step_inline:nn { 10 }
     {
-      \tl_put_right:Nx \l_tmpa_tl
+      \tl_new:c { l_@@_ #1 _tl }
+      \tl_build_put_right:Nx \l_@@_kv_tl
         {
-            #1 .tl_set:N = \exp_not:c { l_@@_ #1 _tl } ,
+            #1 .tl_set:N = \exp_not:c { l_@@_normal_    #1 _tl } ,
            F#1 .tl_set:N = \exp_not:c { l_@@_financial_ #1 _tl } ,
-           T#1 .tl_set:N = \exp_not:c { l_@@_tiangan_ #1 _tl } ,
-           D#1 .tl_set:N = \exp_not:c { l_@@_dizhi_ #1 _tl } ,
-          GZ#1 .tl_set:N = \exp_not:c { l_@@_ganzhi_ #1 _tl } ,
           E \int_eval:n { #1 * 4 }
                .tl_set:N = \exp_not:c { l_@@_ s#1 _tl } ,
         }
     }
-  \int_step_inline:nnn { 11 } { 60 }
-    {
-      \tl_put_right:Nx \l_tmpa_tl
-        { GZ#1 .tl_set:N = \exp_not:c { l_@@_ganzhi_ #1 _tl } , }
-    }
   \clist_map_inline:nn { 0 , 100 , 1000 }
     {
-      \tl_put_right:Nx \l_tmpa_tl
+      \tl_new:c { l_@@_ #1 _tl }
+      \tl_build_put_right:Nx \l_@@_kv_tl
         {
-           #1 .tl_set:N = \exp_not:c { l_@@_ #1 _tl } ,
+           #1 .tl_set:N = \exp_not:c { l_@@_normal_    #1 _tl } ,
           F#1 .tl_set:N = \exp_not:c { l_@@_financial_ #1 _tl } ,
         }
     }
-  \clist_map_inline:nn { 20 , 30 , 40 , 200 }
+  \clist_map_inline:nn
     {
-      \tl_put_right:Nx \l_tmpa_tl
+      20 , 30 , 40 , 200 ,
+      dot , and , parts , year , month , day , hour , minute
+    }
+    {
+      \tl_build_put_right:Nx \l_@@_kv_tl
         { #1 .tl_set:N = \exp_not:c { l_@@_ #1 _tl } , }
     }
+  \tl_build_put_right:Nx \l_@@_kv_tl
+    {
+      -   .tl_set:N = \exp_not:N \l_@@_minus_tl ,
+      -0  .tl_set:N = \exp_not:N \l_@@_null_tl ,
+      E2  .tl_set:N = \exp_not:c { l_@@_normal_     100 _tl } ,
+      E3  .tl_set:N = \exp_not:c { l_@@_normal_    1000 _tl } ,
+      FE2 .tl_set:N = \exp_not:c { l_@@_financial_  100 _tl } ,
+      FE3 .tl_set:N = \exp_not:c { l_@@_financial_ 1000 _tl } ,
+      E44 .tl_set:N = \exp_not:c { l_@@_ s11 _tl }
+    }
+  \tl_build_get:NN \l_@@_kv_tl \l_@@_tmp_tl
+  \cs_set:Npn \@@_tmp:w #1 . #2 \q_stop
+    { , #1 .groups:n = { user } }
+  \clist_map_inline:Nn \l_@@_tmp_tl
+    {
+      \tl_build_put_right:Nx \l_@@_kv_tl
+        { \@@_tmp:w #1 \q_stop }
+    }
+  \tl_build_put_right:Nn \l_@@_kv_tl
+    {
+      ,
+      weekday .tl_set:N = \l_@@_weekday_tl ,
+      weekday .groups:n = { user , pre , weekday } ,
+    }
   \clist_map_inline:nn
+    { mon , tue , wed , thu , fri , sat , sun }
     {
-      dot , and , parts , year , month , day , weekday , hour , minute
-      mon , tue , wed , thu , fri , sat , sun
+      \tl_build_put_right:Nx \l_@@_kv_tl
+        {
+          #1 .tl_set:N = \exp_not:c { l_@@_ #1 _tl } ,
+          #1 .groups:n = { user , pos , day } ,
+        }
     }
+  \int_step_inline:nn { 10 }
     {
-      \tl_put_right:Nx \l_tmpa_tl
-        { #1 .tl_set:N = \exp_not:c { l_@@_ #1 _tl } , }
+      \tl_build_put_right:Nx \l_@@_kv_tl
+        {
+          T#1 .tl_set:N = \exp_not:c { l_@@_ganzhi_ #1 _tl } ,
+          T#1 .groups:n = { user , pre , tiandi } ,
+        }
     }
-\use:x
-  {
-    \group_end:
-    \keys_define:nn { zhnum / options } { \exp_not:o \l_tmpa_tl }
-  }
+  \int_step_inline:nn { 12 }
+    {
+      \tl_build_put_right:Nx \l_@@_kv_tl
+        {
+          D#1 .tl_set:N = \exp_not:c { l_@@_dizhi_ #1 _tl } ,
+          D#1 .groups:n = { user , pre , tiandi } ,
+        }
+    }
+  \int_step_inline:nn { 60 }
+    {
+      \tl_build_put_right:Nx \l_@@_kv_tl
+        {
+          GZ#1 .tl_set:N = \exp_not:c { l_@@_ganzhi_ #1 _tl } ,
+          GZ#1 .groups:n = { user , pos , ganzhi } ,
+        }
+    }
+  \tl_build_end:N \l_@@_kv_tl
+  \exp_args:NNno \group_end:
+\keys_define:nn
+  { zhnum / options }
+  { \l_@@_kv_tl }
 %    \end{macrocode}
 %
 % \begin{macro}[int]
@@ -1417,24 +1536,24 @@
 %   }
 % 将配置文件中的中文数字保存到 \texttt{prop} 变量中。
 %    \begin{macrocode}
-\cs_new_protected:Npn \zhnum_set_digits_map:nn #1#2
-  { \prop_put:Nnn \l_@@_cfg_map_prop {#1} {#2} }
+\cs_new_protected:Npn \zhnum_set_digits_map:nn #1
+  { \prop_put:Nnn \l_@@_cfg_map_prop {#1} }
 \cs_new_protected:Npn \zhnum_set_digits_map:nnn #1#2#3
   {
     \prop_put_if_new:Nnn \l_@@_cfg_map_prop {#1} {#3}
     \prop_put:Nnn \l_@@_cfg_map_var_prop {#1_#2} {#3}
   }
-\cs_new_protected:Npn \zhnum_set_financial_map:nn #1#2
-  { \prop_put:Nnn \l_@@_cfg_map_finan_prop {#1} {#2} }
+\cs_new_protected:Npn \zhnum_set_financial_map:nn #1
+  { \prop_put:Nnn \l_@@_cfg_map_finan_prop {#1} }
 \cs_new_protected:Npn \zhnum_set_financial_map:nnn #1#2#3
   {
     \prop_put_if_new:Nnn \l_@@_cfg_map_finan_prop {#1} {#3}
     \prop_put:Nnn \l_@@_cfg_map_var_prop { financial_#1_#2 } {#3}
   }
-\cs_new_protected:Npn \zhnum_set_tiangan_map:nn #1#2
-  { \prop_put:Nnn \l_@@_cfg_map_ganzhi_prop { tiangan_#1 } {#2} }
-\cs_new_protected:Npn \zhnum_set_dizhi_map:nn #1#2
-  { \prop_put:Nnn \l_@@_cfg_map_ganzhi_prop { dizhi_#1 } {#2} }
+\cs_new_protected:Npn \zhnum_set_tiangan_map:nn #1
+  { \prop_put:Nnn \l_@@_cfg_map_ganzhi_prop { tiangan_#1 } }
+\cs_new_protected:Npn \zhnum_set_dizhi_map:nn #1
+  { \prop_put:Nnn \l_@@_cfg_map_ganzhi_prop { dizhi_#1 } }
 \prop_new:N \l_@@_cfg_map_prop
 \prop_new:N \l_@@_cfg_map_var_prop
 \prop_new:N \l_@@_cfg_map_finan_prop
@@ -1448,7 +1567,6 @@
 %     \zhnum_parse_config:,
 %     \zhnum_check_simp:nn,
 %     \zhnum_check_financial:nn,
-%     \zhnum_set_zero:,
 %     \zhnum_set_week_day:
 %   }
 % 将 \texttt{prop} 表转化到单独的 \texttt{tl} 变量。
@@ -1455,129 +1573,264 @@
 %    \begin{macrocode}
 \cs_new_protected:Npn \zhnum_parse_config:
   {
+    \tl_clear_new:N \l_@@_reset_tl
+    \tl_clear_new:N \l_@@_reset_simp_tl
+    \tl_clear_new:N \l_@@_reset_trad_tl
+    \tl_clear_new:N \l_@@_set_ancient_tl
+    \tl_clear_new:N \l_@@_set_normal_tl
+    \tl_clear_new:N \l_@@_reset_ancient_tl
+    \tl_clear_new:N \l_@@_reset_normal_tl
+    \tl_clear_new:N \l_@@_reset_financial_tl
     \prop_map_function:NN \l_@@_cfg_map_prop \zhnum_check_simp:nn
-    \prop_map_function:NN \l_@@_cfg_map_ganzhi_prop \zhnum_assgin_ganzhi:nn
-    \zhnum_set_zero:
-    \zhnum_set_week_day:
-    \bool_if:NF \l_@@_reset_bool
-      {
-        \zhnum_assgin_const:
-        \bool_set_true:N \l_@@_reset_bool
-      }
+    \zhnum_set_ganzhi:
+    \zhnum_reset_all:
   }
 \cs_new_protected:Npn \zhnum_check_simp:nn #1#2
   {
-    \@@_check_simp_aux:nn {#2} {#1}
-    \prop_get:NnNT \l_@@_cfg_map_finan_prop {#1} \l_tmpa_tl
-      { \exp_args:No \@@_check_simp_aux:nn { \l_tmpa_tl } { financial_ #1 } }
+    \prop_get:NnNTF \l_@@_cfg_map_var_prop
+      { #1_ancient } \l_@@_ancient_tl
+      { \@@_add_reset_ancient:nN {#1} \l_@@_ancient_tl }
+      {
+        \@@_check_simp_aux:nn {#2} {#1}
+        \prop_get:NnNT \l_@@_cfg_map_finan_prop {#1} \l_@@_tmp_tl
+          {
+            \exp_args:No \@@_check_simp_aux:nn
+              { \l_@@_tmp_tl } { financial_ #1 }
+            \@@_add_reset_financial:n {#1}
+          }
+      }
   }
 \cs_new_protected:Npn \@@_check_simp_aux:nn #1#2
   {
-    \prop_get:NnNTF \l_@@_cfg_map_var_prop { #2 _trad } \l_tmpa_tl
+    \prop_get:NnNTF \l_@@_cfg_map_var_prop
+      { #2 _trad } \l_@@_trad_tl
       {
-        \prop_get:NnNF \l_@@_cfg_map_var_prop { #2 _simp } \l_tmpb_tl
-          { \tl_set:Nn \l_tmpb_tl {#1} }
-        \tl_set:cx { l_@@_ #2 _tl }
-          {
-            \exp_not:n { \bool_if:NTF \l_@@_simp_bool }
-              { \exp_not:o \l_tmpb_tl } { \exp_not:o \l_tmpa_tl }
-          }
+        \prop_get:NnNF \l_@@_cfg_map_var_prop
+          { #2 _simp } \l_@@_simp_tl
+          { \tl_set:Nn \l_@@_simp_tl {#1} }
+        \@@_add_reset_simp:nNN
+          {#2} \l_@@_simp_tl \l_@@_trad_tl
       }
-      { \tl_set:cn { l_@@_ #2 _tl } {#1} }
+      { \@@_add_reset:nn {#2} {#1} }
   }
-\cs_new_protected:Npn \zhnum_assgin_const:
+\tl_new:N \l_@@_simp_tl
+\tl_new:N \l_@@_trad_tl
+\tl_new:N \l_@@_ancient_tl
+\cs_new_protected:Npn \@@_add_reset:nn #1#2
   {
-    \prop_map_function:NN \l_@@_cfg_map_prop \zhnum_check_financial:nn
-    \zhnum_set_alias:
+    \tl_put_right:Nx \l_@@_reset_tl
+      {
+        \tl_set:Nn \exp_not:c { l_@@_ #1 _tl }
+          { \exp_not:n {#2} }
+      }
   }
-\cs_new_protected:Npn \zhnum_check_financial:nn #1#2
+\cs_new_protected:Npn \@@_add_reset_simp:nNN #1#2#3
   {
-    \prop_get:NnNTF \l_@@_cfg_map_finan_prop {#1} \l_tmpa_tl
+    \tl_put_right:Nx \l_@@_reset_simp_tl
       {
-        \zhnum_assgin_const_tl:cx { c_@@_ #1 _tl }
-          {
-            \exp_not:n { \bool_if:NTF \l_@@_normal_bool }
-              { \exp_not:c { l_@@_ #1 _tl } }
-              { \exp_not:c { l_@@_financial_ #1 _tl } }
-          }
+        \tl_set:Nn \exp_not:c { l_@@_ #1 _tl }
+          { \exp_not:o {#2} }
       }
+    \tl_put_right:Nx \l_@@_reset_trad_tl
       {
-        \zhnum_assgin_const_tl:cx
-          { c_@@_ #1 _tl } { \exp_not:c { l_@@_ #1 _tl } }
+        \tl_set:Nn \exp_not:c { l_@@_ #1 _tl }
+          { \exp_not:o {#3} }
       }
   }
-\cs_new_protected:Npn \zhnum_set_zero:
+\cs_new_protected:Npn \@@_add_reset_financial:n #1
   {
-    \tl_set:cx { l_@@_0_tl }
+    \tl_put_right:Nx \l_@@_set_normal_tl
       {
-        \exp_not:n { \bool_if:NTF \l_@@_null_bool }
-          { \exp_not:o \l_@@_null_tl } { \exp_not:v { l_@@_0_tl } }
+        \tl_set_eq:NN
+          \exp_not:c { l_@@_normal_ #1 _tl }
+          \exp_not:c { l_@@_ #1 _tl }
       }
+    \tl_put_right:Nx \l_@@_reset_normal_tl
+      {
+        \tl_set_eq:NN
+          \exp_not:c { l_@@_ #1 _tl }
+          \exp_not:c { l_@@_normal_ #1 _tl }
+      }
+    \tl_put_right:Nx \l_@@_reset_financial_tl
+      {
+        \tl_set_eq:NN
+          \exp_not:c { l_@@_ #1 _tl }
+          \exp_not:c { l_@@_financial_ #1 _tl }
+      }
   }
+\cs_new_protected:Npn \@@_add_reset_ancient:nN #1#2
+  {
+    \tl_put_right:Nx \l_@@_reset_ancient_tl
+      {
+        \tl_set:Nn \exp_not:c { l_@@_ #1 _tl }
+          { \exp_not:o {#2} }
+      }
+    \tl_put_right:Nx \l_@@_set_ancient_tl
+      {
+        \tl_concat:NNN
+          \exp_not:c { l_@@_ #1 _tl }
+          \exp_not:c { l_@@_   \str_head:n {#1} _tl }
+          \exp_not:c { l_@@_ 1 \str_tail:n {#1} _tl }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]
+%   {
+%     \zhnum_set_week_day:,
+%     \zhnum_reset_week_day:
+%   }
+%    \begin{macrocode}
 \cs_new_protected:Npn \zhnum_set_week_day:
   {
-    \tl_set:Nx \l_@@_mon_tl
-      { \exp_not:N \c_@@_weekday_tl \exp_not:v { l_@@_1_tl } }
-    \tl_set:Nx \l_@@_tue_tl
-      { \exp_not:N \c_@@_weekday_tl \exp_not:v { l_@@_2_tl } }
-    \tl_set:Nx \l_@@_wed_tl
-      { \exp_not:N \c_@@_weekday_tl \exp_not:v { l_@@_3_tl } }
-    \tl_set:Nx \l_@@_thu_tl
-      { \exp_not:N \c_@@_weekday_tl \exp_not:v { l_@@_4_tl } }
-    \tl_set:Nx \l_@@_fri_tl
-      { \exp_not:N \c_@@_weekday_tl \exp_not:v { l_@@_5_tl } }
-    \tl_set:Nx \l_@@_sat_tl
-      { \exp_not:N \c_@@_weekday_tl \exp_not:v { l_@@_6_tl } }
-    \tl_set:Nx \l_@@_sun_tl
-      { \exp_not:N \c_@@_weekday_tl \exp_not:o \l_@@_day_tl }
+    \cs_set_protected:Npx \zhnum_reset_week_day:
+      {
+        \@@_set_week_day:nn { mon } { 1 }
+        \@@_set_week_day:nn { tue } { 2 }
+        \@@_set_week_day:nn { wed } { 3 }
+        \@@_set_week_day:nn { thu } { 4 }
+        \@@_set_week_day:nn { fri } { 5 }
+        \@@_set_week_day:nn { sat } { 6 }
+        \@@_set_week_day:nn { sun } { day }
+      }
   }
-\clist_map_inline:nn { mon , tue , wed , thu , fri , sat , sun }
-  { \tl_const:cx { c_@@_ #1 _tl } { \exp_not:c { l_@@_ #1 _tl } } }
-\cs_new_protected:Npn \zhnum_assgin_ganzhi:nn #1#2
+\cs_new_eq:NN \zhnum_reset_week_day: \prg_do_nothing:
+\cs_new:Npn \@@_set_week_day:nn #1#2
+  {
+    \tl_set:Nx \exp_not:c { l_@@_ #1 _tl }
+      {
+        \exp_not:N \exp_not:o { \exp_not:N \l_@@_weekday_tl }
+        \exp_not:N \exp_not:n { \exp_not:v { l_@@_ #2 _tl } }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]
+%   {
+%     \zhnum_set_ganzhi:,
+%     \zhnum_reset_ganzhi:
+%   }
+%    \begin{macrocode}
+\cs_new_protected:Npn \zhnum_set_ganzhi:
+  {
+    \prop_map_function:NN
+      \l_@@_cfg_map_ganzhi_prop
+      \@@_add_reset:nn
+  }
+\cs_new_protected:Npn \@@_reset_ganzhi:nn #1#2
   { \tl_set:cn { l_@@_ #1 _tl } {#2} }
 \cs_new:Npn \zhnum_zero_mod:nn #1#2
   { \exp_args:Nf \@@_zero_mod_aux:nn { \int_mod:nn {#1} {#2} } {#2} }
 \cs_new:Npn \@@_zero_mod_aux:nn #1#2
   { \int_compare:nNnTF {#1} = \c_zero_int {#2} {#1} }
-\int_step_inline:nn { 60 }
+\tl_new:c { l_@@_dizhi_ 0 _tl }
+\tl_new:c { l_@@_ganzhi_ 0 _tl }
+\tl_new:c { l_@@_tiangan_ 0 _tl }
+\group_begin:
+\cs_set:Npn \@@_tmp:w #1
   {
-    \tl_const:cx { c_@@_ganzhi_ #1 _tl } { \exp_not:c { l_@@_ganzhi_ #1 _tl } }
-    \tl_set:cx { l_@@_ganzhi_ #1 _tl }
-      {
-        \exp_not:c { l_@@_tiangan_ \zhnum_zero_mod:nn {#1} { 10 } _tl }
-        \exp_not:c { l_@@_dizhi_ \zhnum_zero_mod:nn {#1} { 12 } _tl }
-      }
+    \tl_concat:NNN
+      \exp_not:c { l_@@_ganzhi_ #1 _tl }
+      \exp_not:c { l_@@_tiangan_ \zhnum_zero_mod:nn {#1} { 10 } _tl }
+      \exp_not:c { l_@@_dizhi_   \zhnum_zero_mod:nn {#1} { 12 } _tl }
   }
-\cs_new_eq:cc { c_@@_ganzhi_ 0 _tl } { c_@@_ganzhi_ 60 _tl }
-\cs_new_eq:NN \zhnum_assgin_const_tl:cx \tl_const:cx
-\AtEndOfPackage
+\cs_new_protected:Npx \zhnum_reset_ganzhi:
   {
-    \prop_map_inline:Nn \l_@@_cfg_map_ganzhi_prop
-      { \tl_const:cx { c_@@_ #1 _tl } { \exp_not:c { l_@@_ #1 _tl } } }
-    \cs_new_eq:cc { c_@@_tiangan_ 0 _tl } { c_@@_tiangan_ 10 _tl }
-    \cs_new_eq:cc { c_@@_dizhi_ 0 _tl }   { c_@@_dizhi_ 12 _tl }
-    \cs_set_eq:NN \zhnum_assgin_const_tl:cx \tl_set:cx
+    \tl_set_eq:NN
+      \exp_not:c { l_@@_dizhi_ 0 _tl }
+      \exp_not:c { l_@@_dizhi_ 12 _tl }
+    \tl_set_eq:NN
+      \exp_not:c { l_@@_tiangan_ 0 _tl }
+      \exp_not:c { l_@@_tiangan_ 10 _tl }
+    \int_step_function:nN { 60 } \@@_tmp:w
+    \tl_set_eq:NN
+      \exp_not:c { l_@@_ganzhi_ 0 _tl }
+      \exp_not:c { l_@@_ganzhi_ 60 _tl }
   }
+\group_end:
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[int]{\zhnum_set_alias:}
-% 一些易于使用的别名。
+% \begin{macro}[int]
+%   {
+%     \zhnum_reset_config:,
+%     \zhnum_reset_all:,
+%     \zhnum_reset_style:
+%   }
 %    \begin{macrocode}
-\cs_new_eq:NN \zhnum_set_alias:NN \cs_new_eq:NN
-\cs_new_protected:Npx \zhnum_set_alias:
+\cs_new_protected:Npn \zhnum_reset_config:
+  { \zhnum_load_cfg:o { \l_@@_encoding_str } }
+\cs_new_protected:Npn \zhnum_reset_all:
   {
-    \zhnum_set_alias:NN \exp_not:N \c_@@_zero_tl
-                        \exp_not:c { c_@@_ 0 _tl }
-    \zhnum_set_alias:NN \exp_not:N \c_@@_ten_tl
-                        \exp_not:c { c_@@_ 10 _tl }
-    \zhnum_set_alias:NN \exp_not:N \c_@@_hundred_tl
-                        \exp_not:c { c_@@_ 100 _tl }
-    \zhnum_set_alias:NN \exp_not:N \c_@@_thousand_tl
-                        \exp_not:c { c_@@_ 1000 _tl }
+    \zhnum_reset_main:
+    \zhnum_reset_simp:
+    \zhnum_set_week_day:
+    \zhnum_reset_week_day:
+    \zhnum_reset_ganzhi:
+    \zhnum_reset_normal:
   }
-\AtEndOfPackage
-  { \cs_set_eq:NN \zhnum_set_alias:NN \tl_set_eq:NN }
+\cs_new_protected:Npn \zhnum_reset_main:
+  {
+    \tl_use:N \l_@@_reset_tl
+    \tl_use:N \l_@@_set_normal_tl
+    \tl_concat:NNN
+      \l_@@_reset_normal_tl
+      \l_@@_reset_normal_tl
+      \c_@@_set_zero_tl
+    \tl_concat:NNN
+      \l_@@_reset_financial_tl
+      \l_@@_reset_financial_tl
+      \c_@@_set_zero_tl
+    \tl_concat:NNN
+      \l_@@_reset_financial_tl
+      \l_@@_reset_financial_tl
+      \l_@@_set_ancient_tl
+  }
+\tl_const:Nx \c_@@_set_zero_tl
+  {
+    \tl_set_eq:NN
+      \exp_not:N \l_@@_zero_tl
+      \exp_not:c { l_@@_0_tl }
+  }
+\tl_new:N \l_@@_zero_tl
+\cs_new_protected:Npn \zhnum_reset_style:
+  {
+    \zhnum_reset_simp:
+    \zhnum_reset_normal:
+  }
+\cs_new_protected:Npn \zhnum_reset_simp:
+  {
+    \bool_if:NTF \l_@@_simp_bool
+      { \tl_use:N \l_@@_reset_simp_tl }
+      { \tl_use:N \l_@@_reset_trad_tl }
+  }
+\cs_new_protected:Npn \zhnum_reset_normal:
+  {
+    \bool_if:NTF \l_@@_normal_bool
+      {
+        \tl_use:N \l_@@_reset_normal_tl
+        \@@_reset_ancient:
+        \@@_reset_zero:
+      }
+      { \tl_use:N \l_@@_reset_financial_tl }
+  }
+\cs_new_protected:Npn \@@_reset_ancient:
+  {
+    \bool_if:NTF \l_@@_ancient_bool
+      { \tl_use:N \l_@@_reset_ancient_tl }
+      { \tl_use:N \l_@@_set_ancient_tl }
+  }
+\cs_new_protected:Npx \@@_reset_zero:
+  {
+    \exp_not:n { \bool_if:NT \l_@@_null_bool }
+      {
+        \tl_set_eq:NN
+          \exp_not:c { l_@@_0_tl }
+          \exp_not:N \l_@@_null_tl
+      }
+  }
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1587,38 +1840,49 @@
 \cs_new_protected:Npn \zhnum_load_cfg:n #1
   {
     \zhnum_set_cfg_name:Nn \l_@@_cfg_str {#1}
-    \str_if_eq:NNF \l_@@_cfg_str \l_@@_last_cfg_str
-      { \zhnum_update_cfg:n {#1} }
-    \zhnum_parse_config:
+    \str_if_eq:NNTF \l_@@_cfg_str \l_@@_last_cfg_str
+      { \zhnum_reset_all: }
+      {
+        \zhnum_update_cfg:n {#1}
+        \zhnum_parse_config:
+      }
   }
 \cs_generate_variant:Nn \zhnum_load_cfg:n { o }
 \cs_new_protected:Npn \zhnum_update_cfg:n #1
   {
     \prop_if_exist:cTF { g_@@_cfg_ \l_@@_cfg_str _prop }
-      { \str_set_eq:NN \l_@@_last_cfg_str \l_@@_cfg_str }
+      { \@@_set_cfg_prop: }
       { \zhnum_input_cfg:n {#1} }
+  }
+\cs_new_protected:Npn \@@_set_cfg_prop:
+  {
+    \str_set_eq:NN \l_@@_last_cfg_str \l_@@_cfg_str
     \@@_update_cfg_prop:N \prop_set_eq:Nc
   }
 \cs_new_protected:Npn \zhnum_input_cfg:n #1
   {
-    \file_if_exist:nTF { zhnumber - #1 .cfg }
+    \file_get_full_name:nNTF { zhnumber - #1 .cfg } \l_@@_cfg_file_tl
       {
         \bool_set_false:N \l_@@_reset_bool
         \@@_update_cfg_prop:N \@@_prop_initial:Nn
         \group_begin:
           \zhnum_set_catcode:
-          \file_input:n { zhnumber - #1 .cfg }
+          \exp_args:No \file_input:n { \l_@@_cfg_file_tl }
           \@@_update_cfg_prop:N \@@_prop_gset_eq:Nn
         \group_end:
+        \@@_set_cfg_prop:
       }
       { \msg_error:nnx { zhnumber } { file-not-found } {#1} }
   }
-\cs_new_protected:Npn \@@_update_cfg_prop:N #1
+\tl_new:N \l_@@_cfg_file_tl
+\cs_new_protected:Npn \@@_update_cfg_prop:N
+  { \exp_args:No \@@_update_cfg_prop_aux:nN { \l_@@_cfg_str } }
+\cs_new_protected:Npn \@@_update_cfg_prop_aux:nN #1#2
   {
-    #1 \l_@@_cfg_map_prop        { g_@@_cfg_ \l_@@_cfg_str _prop }
-    #1 \l_@@_cfg_map_var_prop    { g_@@_cfg_var_ \l_@@_cfg_str _prop }
-    #1 \l_@@_cfg_map_finan_prop  { g_@@_cfg_finan_ \l_@@_cfg_str _prop }
-    #1 \l_@@_cfg_map_ganzhi_prop { g_@@_cfg_ganzhi_ \l_@@_cfg_str _prop }
+    #2 \l_@@_cfg_map_prop        { g_@@_cfg_        #1 _prop }
+    #2 \l_@@_cfg_map_var_prop    { g_@@_cfg_var_    #1 _prop }
+    #2 \l_@@_cfg_map_finan_prop  { g_@@_cfg_finan_  #1 _prop }
+    #2 \l_@@_cfg_map_ganzhi_prop { g_@@_cfg_ganzhi_ #1 _prop }
   }
 \cs_new_protected:Npn \@@_prop_initial:Nn #1#2
   {
@@ -1639,24 +1903,19 @@
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[int,pTF]{\zhnum_if_unicode_engine:}
+% \begin{macro}[int]{\c_@@_unicode_engine_bool}
 % 使用 \upTeX{} 的时候,也不必将汉字的首字符设置为活动字符。判断 |^^^^0021| 是否为
 % 单个记号的办法对 \upTeX{} 不适用。
 %    \begin{macrocode}
-\bool_lazy_any:nTF
+\bool_const:Nn \c_@@_unicode_engine_bool
   {
-    { \sys_if_engine_xetex_p:  }
-    { \sys_if_engine_luatex_p: }
-    { \sys_if_engine_uptex_p: }
+    \bool_lazy_any_p:n
+      {
+        { \sys_if_engine_xetex_p:  }
+        { \sys_if_engine_luatex_p: }
+        { \sys_if_engine_uptex_p: }
+      }
   }
-  {
-    \cs_new_eq:NN \zhnum_if_unicode_engine_p: \c_true_bool
-    \cs_new_eq:NN \zhnum_if_unicode_engine:TF \use_i:nn
-  }
-  {
-    \cs_new_eq:NN \zhnum_if_unicode_engine_p: \c_false_bool
-    \cs_new_eq:NN \zhnum_if_unicode_engine:TF \use_ii:nn
-  }
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1668,52 +1927,62 @@
 %   }
 % 设置与恢复配置文件前后的 catcode。\pdfLaTeX{} 需要将汉字的首字节设置为活动字符。
 %    \begin{macrocode}
-\if_predicate:w \zhnum_if_unicode_engine_p:
-  \cs_new_eq:NN \zhnum_set_catcode: \prg_do_nothing:
-  \cs_new_protected:Npn \zhnum_set_cfg_name:Nn #1#2
-    {
-      \str_set:Nx \l_@@_encoding_str {#2}
-      \str_set_eq:NN #1 \l_@@_encoding_str
-    }
-  \cs_new_eq:NN \zhnum_reset_config: \zhnum_parse_config:
-\else:
-  \cs_new_protected:Npn \zhnum_set_catcode:
-    { \bool_if:NT \l_@@_active_char_bool { \zhnum_set_active: } }
-  \cs_new_protected:Npn \zhnum_set_active:
-    {
-      \str_case:onTF { \l_@@_encoding_str }
-        {
-          { gbk }  { \int_set:Nn \l_@@_byte_min_int { "81 } }
-          { big5 } { \int_set:Nn \l_@@_byte_min_int { "A1 } }
-        }
-        { \int_set:Nn \l_@@_byte_max_int { "FE } }
-        {
-          \int_set:Nn \l_@@_byte_min_int { "E0 }
-          \int_set:Nn \l_@@_byte_max_int { "EF }
-        }
-      \int_step_function:nnN
-        { \l_@@_byte_min_int }
-        { \l_@@_byte_max_int } \char_set_catcode_active:n
-    }
-  \int_new:N \l_@@_byte_min_int
-  \int_new:N \l_@@_byte_max_int
-  \cs_new_protected:Npn \zhnum_set_cfg_name:Nn #1#2
-    {
-      \str_set:Nx \l_@@_encoding_str {#2}
-      \str_set:Nx #1
-        {
-          \l_@@_encoding_str
-          \bool_if:NT \l_@@_active_char_bool { _active }
-        }
-    }
-  \cs_new_protected:Npn \zhnum_reset_config:
-    { \zhnum_load_cfg:o { \l_@@_encoding_str } }
-  \bool_new:N \l_@@_active_char_bool
-  \bool_set_true:N \l_@@_active_char_bool
-\fi:
+\bool_if:NTF \c_@@_unicode_engine_bool
+  {
+    \cs_new_eq:NN \zhnum_set_catcode: \prg_do_nothing:
+    \cs_new_protected:Npn \zhnum_set_cfg_name:Nn #1#2
+      {
+        \str_set:Nx \l_@@_encoding_str {#2}
+        \str_set_eq:NN #1 \l_@@_encoding_str
+      }
+  }
+  {
+    \cs_new_protected:Npn \zhnum_set_catcode:
+      {
+        \bool_if:NTF \l_@@_active_char_bool
+          { \zhnum_set_active: }
+          { \zhnum_set_other: }
+      }
+    \cs_new_protected:Npx \zhnum_set_active:
+      {
+        \int_step_function:nnN
+          { 128 } { 255 } \char_set_catcode_active:n
+      }
+    \cs_new_protected:Npx \zhnum_set_other:
+      {
+        \int_step_function:nnN
+          { 128 } { 255 } \char_set_catcode_other:n
+      }
+    \cs_new_protected:Npn \zhnum_set_cfg_name:Nn #1#2
+      {
+        \str_set:Nx \l_@@_encoding_str {#2}
+        \str_set:Nx #1
+          {
+            \l_@@_encoding_str
+            \bool_if:NTF \l_@@_active_char_bool
+              { / active }
+              { / other }
+          }
+      }
+    \bool_new:N \l_@@_active_char_bool
+    \bool_set_true:N \l_@@_active_char_bool
+  }
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}[int]{\zhnum_set_encoding:n}
+% 设置编码。
+%    \begin{macrocode}
+\cs_new_protected:Npn \zhnum_set_encoding:n #1
+  {
+    \str_set:Nx \l_@@_encoding_str
+      { \str_lowercase:n {#1} }
+    \zhnum_load_cfg:o { \l_@@_encoding_str }
+  }
+\str_new:N \l_@@_encoding_str
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}{encoding,style,null,reset}
 % 宏包设置选项。
 %    \begin{macrocode}
@@ -1721,11 +1990,7 @@
   {
     encoding         .choices:nn =
       { UTF8 , GBK , Big5 }
-      {
-        \str_set:Nx \l_@@_encoding_str
-          { \exp_args:No \str_lowercase:n { \l_keys_choice_tl } }
-        \zhnum_load_cfg:o { \l_@@_encoding_str }
-      } ,
+      { \exp_args:No \zhnum_set_encoding:n { \l_keys_choice_tl } } ,
     encoding          .default:n = { GBK } ,
     encoding / Bg5       .meta:n = { encoding = Big5 } ,
     encoding / unknown   .code:n =
@@ -1749,12 +2014,14 @@
     style / Simplified   .code:n = { \bool_set_true:N  \l_@@_simp_bool } ,
     style / Traditional  .code:n = { \bool_set_false:N \l_@@_simp_bool } ,
     style             .default:n = { Normal , Simplified } ,
+    style              .groups:n = { style } ,
     null             .bool_set:N = \l_@@_null_bool ,
+    null               .groups:n = { style } ,
     time .choice: ,
     time / Chinese       .code:n = { \bool_set_true:N \l_@@_time_bool } ,
     time / Arabic        .code:n = { \bool_set_false:N  \l_@@_time_bool } ,
     time              .default:n = { Arabic } ,
-    reset                .code:n = { \zhnum_reset_config: } ,
+    reset            .bool_set:N = \l_@@_reset_bool ,
     activechar       .bool_set:N = \l_@@_active_char_bool ,
     ganzhi-cyclic .choice: ,
     ganzhi-cyclic / true .code:n =
@@ -1764,7 +2031,9 @@
     ganzhi-cyclic     .default:n = { true } ,
     arabicsep          .tl_set:N = \l_@@_arabic_sep_tl
   }
-\str_new:N \l_@@_encoding_str
+\bool_new:N \l_@@_simp_bool
+\bool_new:N \l_@@_normal_bool
+\bool_new:N \l_@@_ancient_bool
 \msg_new:nnnn { zhnumber } { encoding-invalid }
   { The~encoding~`#1'~is~invalid. }
   { Available~encodings~are~`UTF8',~`GBK'~and~`Big5'. }
@@ -1776,26 +2045,74 @@
 %    \begin{macrocode}
 \NewDocumentCommand \zhnumsetup { +m }
   {
-    \keys_set:nn { zhnum / options } {#1}
+    \zhnum_set:n {#1}
     \tex_ignorespaces:D
   }
+\cs_new_protected:Npn \zhnum_set:n #1
+  {
+    \bool_set_false:N \l_@@_reset_bool
+    \keys_set_filter:nnnN { zhnum / options }
+      { style , user } {#1} \l_@@_kv_tl
+    \tl_if_empty:NF \l_@@_kv_tl
+      { \@@_set_style: }
+    \bool_if:NT \l_@@_reset_bool
+      { \zhnum_reset_config: }
+  }
+\cs_new_protected:Npn \@@_set_style:
+  {
+    \keys_set_filter:nnoN { zhnum / options }
+      { user } { \l_@@_kv_tl } \l_@@_tmp_tl
+    \tl_if_empty:NTF \l_@@_tmp_tl
+      { \zhnum_reset_style: }
+      {
+        \tl_if_eq:NNF \l_@@_tmp_tl \l_@@_kv_tl
+          { \zhnum_reset_style: }
+        \bool_if:NF \l_@@_reset_bool
+          { \@@_set_user: }
+      }
+  }
+\cs_new_protected:Npn \@@_set_user:
+  {
+    \keys_set_filter:nnoN { zhnum / options }
+      { pre , pos } { \l_@@_tmp_tl } \l_@@_kv_tl
+    \tl_if_eq:NNF \l_@@_kv_tl \l_@@_tmp_tl
+      { \zhnum_reset_normal: }
+    \tl_if_empty:NF \l_@@_kv_tl
+      { \@@_set_pre_pos: }
+  }
+\cs_new_protected:Npn \@@_set_pre_pos:
+  {
+    \keys_set_filter:nnoN { zhnum / options }
+      { pos } { \l_@@_kv_tl } \l_@@_tmp_tl
+    \tl_if_eq:NNF \l_@@_tmp_tl \l_@@_kv_tl
+      {
+        \zhnum_reset_week_day:
+        \zhnum_reset_ganzhi:
+      }
+    \tl_if_empty:NF \l_@@_kv_tl
+      { \keys_set:no { zhnum / options } { \l_@@_kv_tl } }
+  }
+\cs_generate_variant:Nn \keys_set_filter:nnnN { nno }
 %    \end{macrocode}
 % \end{macro}
 %
 % 初始化设置和执行宏包选项。
 %    \begin{macrocode}
-\keys_set:nn { zhnum / options } { style , time , arabicsep = { ~ } }
-\ProcessKeysOptions { zhnum / options }
+\keys_set:nn { zhnum / options }
+  { style , time , arabicsep = { ~ } }
+\cs_if_exist:NTF \ProcessKeyOptions
+  { \ProcessKeyOptions [ zhnum / options ] }
+  {
+    \RequirePackage { l3keys2e }
+    \ProcessKeysOptions { zhnum / options }
+  }
 %    \end{macrocode}
 %
-% 如果没有选定编码,则根据引擎自动设置编码。
+% 如果没有选定编码,则选用 |UTF8|。
 %    \begin{macrocode}
-\str_if_empty:NT \l_@@_encoding_str
-  {
-    \zhnum_if_unicode_engine:TF
-      { \keys_set:nn { zhnum / options } { encoding = UTF8 } }
-      { \keys_set:nn { zhnum / options } { encoding = GBK } }
-  }
+\str_if_empty:NTF \l_@@_encoding_str
+  { \zhnum_set_encoding:n { UTF8 } }
+  { \zhnum_reset_style: }
 %    \end{macrocode}
 %
 %    \begin{macrocode}
@@ -1836,10 +2153,10 @@
 \zhnum_set_digits_map:nn { 10 }    { 十 }
 \zhnum_set_digits_map:nn { 100 }   { 百 }
 \zhnum_set_digits_map:nn { 1000 }  { 千 }
-\zhnum_set_digits_map:nn { 20 }    { 廿 }
-\zhnum_set_digits_map:nn { 30 }    { 卅 }
-\zhnum_set_digits_map:nn { 40 }    { 卌 }
-\zhnum_set_digits_map:nn { 200 }   { 皕 }
+\zhnum_set_digits_map:nnn { 20 }   { ancient } { 廿 }
+\zhnum_set_digits_map:nnn { 30 }   { ancient } { 卅 }
+\zhnum_set_digits_map:nnn { 40 }   { ancient } { 卌 }
+\zhnum_set_digits_map:nnn { 200 }  { ancient } { 皕 }
 %<*!big5>
 \zhnum_set_digits_map:nnn { dot } { simp } { 点 }
 \zhnum_set_digits_map:nnn { dot } { trad } { 點 }

Modified: trunk/Master/texmf-dist/source/latex/zhnumber/zhnumber.ins
===================================================================
--- trunk/Master/texmf-dist/source/latex/zhnumber/zhnumber.ins	2022-07-14 20:21:15 UTC (rev 63897)
+++ trunk/Master/texmf-dist/source/latex/zhnumber/zhnumber.ins	2022-07-14 20:21:27 UTC (rev 63898)
@@ -6,7 +6,7 @@
 %%
 %% zhnumber.dtx  (with options: `install')
 %% 
-%%     Copyright (C) 2012, 2014-2020 by Qing Lee <sobenlee at gmail.com>
+%%     Copyright (C) 2012, 2014-2020, 2022 by Qing Lee <sobenlee at gmail.com>
 %% --------------------------------------------------------------------------
 %% 
 %%     This work may be distributed and/or modified under the
@@ -30,7 +30,7 @@
 
 \preamble
 
-    Copyright (C) 2012, 2014-2020 by Qing Lee <sobenlee at gmail.com>
+    Copyright (C) 2012, 2014-2020, 2022 by Qing Lee <sobenlee at gmail.com>
 --------------------------------------------------------------------------
 
     This work may be distributed and/or modified under the

Modified: trunk/Master/texmf-dist/tex/latex/zhnumber/zhnumber-big5.cfg
===================================================================
--- trunk/Master/texmf-dist/tex/latex/zhnumber/zhnumber-big5.cfg	2022-07-14 20:21:15 UTC (rev 63897)
+++ trunk/Master/texmf-dist/tex/latex/zhnumber/zhnumber-big5.cfg	2022-07-14 20:21:27 UTC (rev 63898)
@@ -6,7 +6,7 @@
 %%
 %% zhnumber.dtx  (with options: `config,big5')
 %% 
-%%     Copyright (C) 2012, 2014-2020 by Qing Lee <sobenlee at gmail.com>
+%%     Copyright (C) 2012, 2014-2020, 2022 by Qing Lee <sobenlee at gmail.com>
 %% --------------------------------------------------------------------------
 %% 
 %%     This work may be distributed and/or modified under the
@@ -25,10 +25,10 @@
 %% 
 %% --------------------------------------------------------------------------
 %% 
-\GetIdInfo$Id: zhnumber.dtx c4664c6 2020-05-01 21:10:24 +0800 Qing Lee <sobenlee at gmail.com> $
+\GetIdInfo$Id: zhnumber.dtx 5e8c3fe 2022-07-14 18:53:36 +0800 Qing Lee <sobenlee at gmail.com> $
   {Chinese numerals with Big5 encoding}
 \ProvidesExplFile{\ExplFileName-big5.cfg}
-  {\ExplFileDate}{2.8}{\ExplFileDescription}
+  {\ExplFileDate}{3.0}{\ExplFileDescription}
 \zhnum_set_digits_map:nn { minus } { \xADt }
 \zhnum_set_digits_map:nn { 0 }     { \xB9s }
 \zhnum_set_digits_map:nn { null }  { \xA1\xB3 }
@@ -44,10 +44,10 @@
 \zhnum_set_digits_map:nn { 10 }    { \xA4Q }
 \zhnum_set_digits_map:nn { 100 }   { \xA6\xCA }
 \zhnum_set_digits_map:nn { 1000 }  { \xA4d }
-\zhnum_set_digits_map:nn { 20 }    { \xA4\xDC }
-\zhnum_set_digits_map:nn { 30 }    { \xA4\xCA }
-\zhnum_set_digits_map:nn { 40 }    { \xC9m }
-\zhnum_set_digits_map:nn { 200 }   { ڷ }
+\zhnum_set_digits_map:nnn { 20 }   { ancient } { \xA4\xDC }
+\zhnum_set_digits_map:nnn { 30 }   { ancient } { \xA4\xCA }
+\zhnum_set_digits_map:nnn { 40 }   { ancient } { \xC9m }
+\zhnum_set_digits_map:nnn { 200 }  { ancient } { ڷ }
 \zhnum_set_digits_map:nn { dot }   { \xC2I }
 \zhnum_set_digits_map:nn { and }   { \xA4S }
 \zhnum_set_digits_map:nn { parts } { \xA4\xC0\xA4\xA7 }

Modified: trunk/Master/texmf-dist/tex/latex/zhnumber/zhnumber-gbk.cfg
===================================================================
--- trunk/Master/texmf-dist/tex/latex/zhnumber/zhnumber-gbk.cfg	2022-07-14 20:21:15 UTC (rev 63897)
+++ trunk/Master/texmf-dist/tex/latex/zhnumber/zhnumber-gbk.cfg	2022-07-14 20:21:27 UTC (rev 63898)
@@ -6,7 +6,7 @@
 %%
 %% zhnumber.dtx  (with options: `config,gbk')
 %% 
-%%     Copyright (C) 2012, 2014-2020 by Qing Lee <sobenlee at gmail.com>
+%%     Copyright (C) 2012, 2014-2020, 2022 by Qing Lee <sobenlee at gmail.com>
 %% --------------------------------------------------------------------------
 %% 
 %%     This work may be distributed and/or modified under the
@@ -25,10 +25,10 @@
 %% 
 %% --------------------------------------------------------------------------
 %% 
-\GetIdInfo$Id: zhnumber.dtx c4664c6 2020-05-01 21:10:24 +0800 Qing Lee <sobenlee at gmail.com> $
+\GetIdInfo$Id: zhnumber.dtx 5e8c3fe 2022-07-14 18:53:36 +0800 Qing Lee <sobenlee at gmail.com> $
   {Chinese numerals with GBK encoding}
 \ProvidesExplFile{\ExplFileName-gbk.cfg}
-  {\ExplFileDate}{2.8}{\ExplFileDescription}
+  {\ExplFileDate}{3.0}{\ExplFileDescription}
 \zhnum_set_digits_map:nnn { minus } { simp } { \xB8\xBA }
 \zhnum_set_digits_map:nnn { minus } { trad } { ؓ }
 \zhnum_set_digits_map:nn { 0 }     { \xC1\xE3 }
@@ -45,10 +45,10 @@
 \zhnum_set_digits_map:nn { 10 }    { ʮ }
 \zhnum_set_digits_map:nn { 100 }   { \xB0\xD9 }
 \zhnum_set_digits_map:nn { 1000 }  { ǧ }
-\zhnum_set_digits_map:nn { 20 }    { إ }
-\zhnum_set_digits_map:nn { 30 }    { ئ }
-\zhnum_set_digits_map:nn { 40 }    { \x85c }
-\zhnum_set_digits_map:nn { 200 }   { \xB0z }
+\zhnum_set_digits_map:nnn { 20 }   { ancient } { إ }
+\zhnum_set_digits_map:nnn { 30 }   { ancient } { ئ }
+\zhnum_set_digits_map:nnn { 40 }   { ancient } { \x85c }
+\zhnum_set_digits_map:nnn { 200 }  { ancient } { \xB0z }
 \zhnum_set_digits_map:nnn { dot } { simp } { \xB5\xE3 }
 \zhnum_set_digits_map:nnn { dot } { trad } { \xFCc }
 \zhnum_set_digits_map:nn { and }   { \xD3\xD6 }

Modified: trunk/Master/texmf-dist/tex/latex/zhnumber/zhnumber-utf8.cfg
===================================================================
--- trunk/Master/texmf-dist/tex/latex/zhnumber/zhnumber-utf8.cfg	2022-07-14 20:21:15 UTC (rev 63897)
+++ trunk/Master/texmf-dist/tex/latex/zhnumber/zhnumber-utf8.cfg	2022-07-14 20:21:27 UTC (rev 63898)
@@ -6,7 +6,7 @@
 %%
 %% zhnumber.dtx  (with options: `config,utf8')
 %% 
-%%     Copyright (C) 2012, 2014-2020 by Qing Lee <sobenlee at gmail.com>
+%%     Copyright (C) 2012, 2014-2020, 2022 by Qing Lee <sobenlee at gmail.com>
 %% --------------------------------------------------------------------------
 %% 
 %%     This work may be distributed and/or modified under the
@@ -25,10 +25,10 @@
 %% 
 %% --------------------------------------------------------------------------
 %% 
-\GetIdInfo$Id: zhnumber.dtx c4664c6 2020-05-01 21:10:24 +0800 Qing Lee <sobenlee at gmail.com> $
+\GetIdInfo$Id: zhnumber.dtx 5e8c3fe 2022-07-14 18:53:36 +0800 Qing Lee <sobenlee at gmail.com> $
   {Chinese numerals with UTF8 encoding}
 \ProvidesExplFile{\ExplFileName-utf8.cfg}
-  {\ExplFileDate}{2.8}{\ExplFileDescription}
+  {\ExplFileDate}{3.0}{\ExplFileDescription}
 \zhnum_set_digits_map:nnn { minus } { simp } { 负 }
 \zhnum_set_digits_map:nnn { minus } { trad } { 負 }
 \zhnum_set_digits_map:nn { 0 }     { 零 }
@@ -45,10 +45,10 @@
 \zhnum_set_digits_map:nn { 10 }    { 十 }
 \zhnum_set_digits_map:nn { 100 }   { 百 }
 \zhnum_set_digits_map:nn { 1000 }  { 千 }
-\zhnum_set_digits_map:nn { 20 }    { 廿 }
-\zhnum_set_digits_map:nn { 30 }    { 卅 }
-\zhnum_set_digits_map:nn { 40 }    { 卌 }
-\zhnum_set_digits_map:nn { 200 }   { 皕 }
+\zhnum_set_digits_map:nnn { 20 }   { ancient } { 廿 }
+\zhnum_set_digits_map:nnn { 30 }   { ancient } { 卅 }
+\zhnum_set_digits_map:nnn { 40 }   { ancient } { 卌 }
+\zhnum_set_digits_map:nnn { 200 }  { ancient } { 皕 }
 \zhnum_set_digits_map:nnn { dot } { simp } { 点 }
 \zhnum_set_digits_map:nnn { dot } { trad } { 點 }
 \zhnum_set_digits_map:nn { and }   { 又 }

Modified: trunk/Master/texmf-dist/tex/latex/zhnumber/zhnumber.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/zhnumber/zhnumber.sty	2022-07-14 20:21:15 UTC (rev 63897)
+++ trunk/Master/texmf-dist/tex/latex/zhnumber/zhnumber.sty	2022-07-14 20:21:27 UTC (rev 63898)
@@ -6,7 +6,7 @@
 %%
 %% zhnumber.dtx  (with options: `package')
 %% 
-%%     Copyright (C) 2012, 2014-2020 by Qing Lee <sobenlee at gmail.com>
+%%     Copyright (C) 2012, 2014-2020, 2022 by Qing Lee <sobenlee at gmail.com>
 %% --------------------------------------------------------------------------
 %% 
 %%     This work may be distributed and/or modified under the
@@ -27,10 +27,10 @@
 %% 
 \NeedsTeXFormat{LaTeX2e}
 \RequirePackage{expl3}
-\GetIdInfo$Id: zhnumber.dtx c4664c6 2020-05-01 21:10:24 +0800 Qing Lee <sobenlee at gmail.com> $
+\GetIdInfo$Id: zhnumber.dtx 5e8c3fe 2022-07-14 18:53:36 +0800 Qing Lee <sobenlee at gmail.com> $
   {Typesetting numbers with Chinese glyphs}
 \ProvidesExplPackage{\ExplFileName}
-  {\ExplFileDate}{2.8}{\ExplFileDescription}
+  {\ExplFileDate}{3.0}{\ExplFileDescription}
 \msg_new:nnn { zhnumber } { l3-too-old }
   {
     Support~package~'expl3'~too~old. \\\\
@@ -40,11 +40,34 @@
   }
 \@ifpackagelater { expl3 } { 2019/03/05 } { }
   { \msg_error:nn  { zhnumber }  { l3-too-old } }
-\RequirePackage { xparse , l3keys2e }
-\DeclareExpandableDocumentCommand \zhnumber { +o +m }
+\cs_if_exist:NF \NewDocumentCommand
+  { \RequirePackage { xparse } }
+\cs_new:Npn \zhnum_output:n #1
+  { \exp_args:Nc \zhnum_exp_not:o { l__zhnum_ #1 _tl } }
+\cs_new_protected:Npn \zhnum_expand_wrap:wn #1#
+  { \__zhnum_expand_wrap_aux:nn {#1} }
+\cs_new_protected:Npn \__zhnum_expand_wrap_aux:nn #1#2
+  { #1 { \exp_not:e {#2} } }
+\cs_new_eq:NN \zhnum_exp_not:e \exp_not:e
+\cs_new_eq:NN \zhnum_exp_not:o \exp_not:o
+\cs_new_protected:Npn \zhnumClearWrapper
   {
-    \IfNoValueTF {#1}
-      { \zhnum_number:f }
+    \cs_set_eq:NN \zhnum_exp_not:e \use:n
+    \cs_set_eq:NN \zhnum_exp_not:o \use:n
+  }
+\cs_new_protected:Npn \zhnumResetWrapper
+  {
+    \cs_set_eq:NN \zhnum_exp_not:e \exp_not:e
+    \cs_set_eq:NN \zhnum_exp_not:o \exp_not:o
+  }
+\hook_gput_code:nnn { package/CJKutf8/after } { zhnumber }
+  { \g at addto@macro \pdfstringdefPreHook { \zhnumClearWrapper } }
+\hook_gput_code:nnn { package/xCJK2uni/after } { zhnumber }
+  { \g at addto@macro \pdfstringdefPreHook { \zhnumClearWrapper } }
+\NewExpandableDocumentCommand \zhnumber { +o +m }
+  {
+    \tl_if_novalue:nTF {#1}
+      { \zhnum_number:e }
       { \zhnumberwithoptions {#1} }
     {#2}
   }
@@ -51,10 +74,11 @@
  \NewDocumentCommand \zhnumberwithoptions { +m +m }
   {
     \group_begin:
-      \keys_set:nn { zhnum / options } {#1}
-      \zhnum_number:f {#2}
+      \zhnum_set:n {#1}
+      \zhnum_number:e {#2}
     \group_end:
   }
+\zhnum_expand_wrap:wn
 \cs_new:Npn \zhnum_number:n #1
   { \__zhnum_number:www #1 . \q_nil . \q_stop }
 \cs_new:Npn \__zhnum_number:www #1 . #2 . #3 \q_stop
@@ -63,7 +87,7 @@
       { \__zhnum_integer_or_fraction:www #1 / \q_nil / \q_stop }
       { \zhnum_decimal:nn {#1} {#2} }
   }
-\cs_generate_variant:Nn \zhnum_number:n { f }
+\cs_generate_variant:Nn \zhnum_number:n { e }
 \cs_new:Npn \__zhnum_integer_or_fraction:www #1 / #2 / #3 \q_stop
   {
     \quark_if_nil:nTF {#2}
@@ -75,7 +99,7 @@
     \quark_if_nil:nTF {#3}
       {
         \zhnum_blank_to_zero:n {#1}
-        \c__zhnum_parts_tl
+        \zhnum_output:n { parts }
         \zhnum_blank_to_zero:n {#2}
       }
       {
@@ -82,29 +106,30 @@
         \tl_if_blank:nF {#2}
           {
             \zhnum_number:n {#2}
-            \c__zhnum_and_tl
+            \zhnum_output:n { and }
           }
         \zhnum_blank_to_zero:n {#1}
-        \c__zhnum_parts_tl
+        \zhnum_output:n { parts }
         \zhnum_blank_to_zero:n {#3}
       }
   }
 \cs_new:Npn \zhnum_decimal:nn #1#2
   {
-    \zhnum_blank_to_zero:n {#1} \c__zhnum_dot_tl
+    \zhnum_blank_to_zero:n {#1}
+    \zhnum_output:n { dot }
     \tl_if_blank:nTF {#2}
-      { \c__zhnum_zero_tl }
+      { \zhnum_output:n { 0 } }
       { \zhnum_digits_zero:n {#2} }
   }
 \cs_new:Npn \zhnum_blank_to_zero:n #1
   {
     \tl_if_blank:nTF {#1}
-      { \c__zhnum_zero_tl }
+      { \zhnum_output:n { 0 } }
       { \zhnum_number:n {#1} }
   }
-\DeclareExpandableDocumentCommand \zhnum { +o +m }
+\NewExpandableDocumentCommand \zhnum { +o +m }
   {
-    \IfNoValueTF {#1}
+    \tl_if_novalue:nTF {#1}
       { \zhnum_counter:n }
       { \zhnumwithoptions {#1} }
     {#2}
@@ -112,7 +137,7 @@
 \NewDocumentCommand \zhnumwithoptions { +m +m }
   {
     \group_begin:
-      \keys_set:nn { zhnum / options } {#1}
+      \zhnum_set:n {#1}
       \zhnum_counter:n {#2}
     \group_end:
   }
@@ -126,6 +151,7 @@
   { \msg_expandable_error:nnn { zhnumber } { not-counter } {#1} }
 \msg_new:nnn  { zhnumber } { not-counter }
   { `#1'~is~not~a~LaTeX~counter. }
+\zhnum_expand_wrap:wn
 \cs_new:Npn \zhnum_int:n #1
   {
     \int_compare:nNnTF {#1} > \c_zero_int
@@ -133,10 +159,10 @@
       {
         \int_compare:nNnTF {#1} < \c_zero_int
           {
-            \c__zhnum_minus_tl
+            \zhnum_output:n { minus }
             \zhnum_parse_number:f { \int_eval:n { - #1 } }
           }
-          { \c__zhnum_zero_tl }
+          { \zhnum_output:n { 0 } }
       }
   }
 \cs_new:Npn \@zhnum { \zhnum_int:n }
@@ -186,10 +212,10 @@
 \cs_new:Npn \__zhnum_read_integer:www #1 ; #2 ; #3 ;
   {
     \int_compare:nNnTF {#2} = \c_zero_int
-      { \c__zhnum_zero_tl }
+      { \zhnum_output:n { 0 } }
       {
         \int_compare:nNnF {#1} = \c_one_int
-          { \c__zhnum_minus_tl }
+          { \zhnum_output:n { minus } }
         \zhnum_parse_number:nn {#2} {#3}
       }
   }
@@ -208,7 +234,7 @@
 \cs_new:Npn \__zhnum_parse_number:nnn #1#2
   {
     \int_compare:nNnTF {#2} < 2
-      { \zhnum_digit_map:n }
+      { \zhnum_output:n }
       {
         \int_compare:nNnTF {#1} = \c_zero_int
           { \zhnum_split_number:fn { \int_eval:n { #2 / 4 - 1 } } }
@@ -241,7 +267,7 @@
     \int_compare:nNnTF { #4#5#6#7 } = \c_zero_int
       { \use_i:nn }
       {
-        \bool_if:NF #1 { \c__zhnum_zero_tl }
+        \bool_if:NF #1 { \zhnum_output:n { 0 } }
         \zhnum_process_number:NNNNNN #4#5#6#7#1#2
         \zhnum_scale_map:n {#3}
         \int_compare:nNnTF {#7} = \c_zero_int
@@ -254,21 +280,34 @@
 \cs_new:Npn \zhnum_process_number:NNNNNN #1#2#3#4#5#6
   {
     \int_compare:nNnTF {#1} = \c_zero_int
-      { \bool_if:NF #6 { \c__zhnum_zero_tl } }
-      { \zhnum_digit_map:n {#1} \c__zhnum_thousand_tl }
+      {
+        \bool_if:NF #6
+          { \zhnum_output:n { 0 } }
+      }
+      {
+        \zhnum_output:n {#1}
+        \zhnum_output:n { 1000 }
+      }
     \int_compare:nNnTF {#2} = \c_zero_int
-      { \int_compare:nNnF { #1 * (#3#4) } = \c_zero_int { \c__zhnum_zero_tl } }
       {
-        \bool_lazy_and:nnTF
-          { \l__zhnum_ancient_bool }
-          { \int_compare_p:nNn {#2} = 2 }
-          { \zhnum_digit_map:n { #2 00 } }
-          { \zhnum_digit_map:n {#2} \c__zhnum_hundred_tl }
+        \int_compare:nNnF { #1 * (#3#4) } = \c_zero_int
+          { \zhnum_output:n { 0 } }
       }
+      {
+        \int_compare:nNnTF {#2} = 2
+          { \zhnum_output:n { 200 } }
+          {
+            \zhnum_output:n {#2}
+            \zhnum_output:n { 100 }
+          }
+      }
     \int_compare:nNnTF {#3} = \c_zero_int
-      { \int_compare:nNnF { #2 * #4 } = \c_zero_int { \c__zhnum_zero_tl } }
       {
-        \bool_lazy_all:nF
+        \int_compare:nNnF { #2 * #4 } = \c_zero_int
+          { \zhnum_output:n { 0 } }
+      }
+      {
+        \bool_lazy_all:nTF
           {
             { \int_compare_p:nNn {#3}   = \c_one_int }
             { \int_compare_p:nNn {#1#2} = \c_zero_int }
@@ -275,20 +314,22 @@
             {#6}
             {#5}
           }
+          { \zhnum_output:n { 10 } }
           {
-            \bool_lazy_and:nnTF
-              { \l__zhnum_ancient_bool }
-              { \int_compare_p:n { 1 < #3 < 5 } }
-              { \zhnum_digit_map:n { #3 0 } \use_none:n }
-              { \zhnum_digit_map:n {#3} }
+            \int_compare:nTF { 1 < #3 < 5 }
+              { \zhnum_output:n { #3 0 } }
+              {
+                \zhnum_output:n {#3}
+                \zhnum_output:n { 10 }
+              }
           }
-        \c__zhnum_ten_tl
       }
-    \int_compare:nNnF {#4} = \c_zero_int { \zhnum_digit_map:n {#4} }
+    \int_compare:nNnF {#4} = \c_zero_int
+      { \zhnum_output:n {#4} }
   }
-\DeclareExpandableDocumentCommand \zhdig { +o +m }
+\NewExpandableDocumentCommand \zhdig { +o +m }
   {
-    \IfNoValueTF {#1}
+    \tl_if_novalue:nTF {#1}
       { \zhnum_digits_counter:n }
       { \zhdigwithoptions {#1} }
     {#2}
@@ -296,7 +337,7 @@
 \NewDocumentCommand \zhdigwithoptions { +m +m }
   {
     \group_begin:
-      \keys_set:nn { zhnum / options } {#1}
+      \zhnum_set:n {#1}
       \zhnum_digits_counter:n #1 {#2}
     \group_end:
   }
@@ -306,11 +347,12 @@
       { \zhnum_digits_null:v { c@#1 } }
       { \__zhnum_counter_error:n {#1} }
   }
-\cs_new:Npn \@zhdig #1 { \zhnum_digits_null:f { \int_eval:n {#1} } }
-\DeclareExpandableDocumentCommand \zhdigits { +s +o +m }
+\cs_new:Npn \@zhdig #1
+  { \zhnum_digits_null:f { \int_eval:n {#1} } }
+\NewExpandableDocumentCommand \zhdigits { +s +o +m }
   {
-    \IfNoValueTF {#2}
-      { \zhnum_digits:Nn #1 }
+    \tl_if_novalue:nTF {#2}
+      { \zhnum_digits:Ne #1 }
       { \zhdigitswithoptions {#1} {#2} }
     {#3}
   }
@@ -317,15 +359,16 @@
 \NewDocumentCommand \zhdigitswithoptions { +m +m +m }
   {
     \group_begin:
-      \keys_set:nn { zhnum / options } {#2}
-      \zhnum_digits:Nn #1 {#3}
+      \zhnum_set:n {#2}
+      \zhnum_digits:Ne #1 {#3}
     \group_end:
   }
 \cs_new:Npn \zhnum_digits_zero:n
-  { \zhnum_digits:Nn \BooleanTrue }
+  { \zhnum_digits:Nn \c_true_bool }
 \cs_new:Npn \zhnum_digits_null:n
-  { \zhnum_digits:Nn \BooleanFalse }
-\cs_generate_variant:Nn \zhnum_digits_null:n { V , v , f }
+  { \zhnum_digits:Nn \c_false_bool }
+\cs_generate_variant:Nn \zhnum_digits_null:n { v , f }
+\zhnum_expand_wrap:wn
 \cs_new:Npn \zhnum_digits:Nn #1#2
   {
     \exp_after:wN \__zhnum_read_digits:w
@@ -352,7 +395,8 @@
       { \__zhnum_output_digits:NN #1#2 }
       {
         \quark_if_recursion_tail_stop:N #2
-        \if:w .\exp_not:N #2 \exp_after:wN \c__zhnum_dot_tl \fi:
+        \token_if_eq_charcode:NNT #2 .
+          { \zhnum_output:n { dot } }
       }
     \exp_after:wN \__zhnum_read_digits_loop:NN \exp_after:wN #1
       \exp:w \exp_end_continue_f:w \use:n
@@ -360,30 +404,34 @@
 \cs_new:Npn \__zhnum_read_digits:w #1 ;
   {
     \int_compare:nNnF {#1} = \c_one_int
-      { \c__zhnum_minus_tl }
+      { \zhnum_output:n { minus } }
   }
 \cs_new:Npn \__zhnum_output_digits:NN #1#2
   {
-    \cs:w
-      c__zhnum_
+    \zhnum_output:n
+      {
         \if_int_compare:w #2 = \c_zero_int
-          \IfBooleanTF #1 { zero } { null }
+          \bool_if:NTF #1 { zero } { null }
         \else:
           #2
         \fi:
-      _tl
-    \cs_end:
+      }
   }
-\DeclareExpandableDocumentCommand \zhdate { +s +m }
+\cs_generate_variant:Nn \zhnum_digits:Nn { Ne }
+\NewExpandableDocumentCommand \zhdate { +s +m }
   {
     \__zhnum_date:www #2 \q_stop
-    \IfBooleanT #1
-      { \__zhnum_week_day:www #2 \q_stop }
+    \bool_if:NT #1 { \__zhnum_week_day:www #2 \q_stop }
   }
 \cs_new:Npn \__zhnum_date:www #1/#2/#3 \q_stop
   { \__zhnum_date_aux:nnn {#1} {#2} {#3} }
 \cs_new:Npn \zhtoday
-  { \__zhnum_date_aux:Vnn \tex_year:D \tex_month:D \tex_day:D }
+  {
+    \__zhnum_date_aux:nnn
+      { \int_value:w \tex_year:D }
+      { \tex_month:D }
+      { \tex_day:D }
+  }
 \cs_new:Npn \__zhnum_date_aux:nnn
   {
     \bool_if:NTF \l__zhnum_time_bool
@@ -390,27 +438,28 @@
       { \__zhnum_date_aux:NNnnnn \zhnum_digits_null:n \zhnum_int:n { } }
       { \__zhnum_date_aux:Nnnnn \int_to_arabic:n { \l__zhnum_arabic_sep_tl } }
   }
-\cs_new:Npn \__zhnum_date_aux:Nnnnn #1
-  { \__zhnum_date_aux:NNnnnn #1#1 }
+\cs_new:Npn \__zhnum_date_aux:Nnnnn #1#2
+  { \__zhnum_date_aux:NNnnnn #1#1 { \zhnum_exp_not:o {#2} } }
+\zhnum_expand_wrap:wn
 \cs_new:Npn \__zhnum_date_aux:NNnnnn #1#2#3#4#5#6
   {
-    #1 {#4} #3 \c__zhnum_year_tl  #3
-    #2 {#5} #3 \c__zhnum_month_tl #3
-    #2 {#6} #3 \c__zhnum_day_tl
+    #1 {#4} #3 \zhnum_output:n { year }  #3
+    #2 {#5} #3 \zhnum_output:n { month } #3
+    #2 {#6} #3 \zhnum_output:n { day }
   }
-\cs_generate_variant:Nn \__zhnum_date_aux:nnn { V }
 \cs_new:Npn \zhweekday #1
   { \__zhnum_week_day:www #1 \q_stop }
+\zhnum_expand_wrap:wn
 \cs_new:Npn \__zhnum_week_day:www #1/#2/#3 \q_stop
   {
     \if_case:w \zhnum_Zeller:nnn {#1} {#2} {#3} \exp_stop_f:
-           \c__zhnum_sat_tl
-      \or: \c__zhnum_sun_tl
-      \or: \c__zhnum_mon_tl
-      \or: \c__zhnum_tue_tl
-      \or: \c__zhnum_wed_tl
-      \or: \c__zhnum_thu_tl
-      \or: \c__zhnum_fri_tl
+           \zhnum_output:n { sat }
+      \or: \zhnum_output:n { sun }
+      \or: \zhnum_output:n { mon }
+      \or: \zhnum_output:n { tue }
+      \or: \zhnum_output:n { wed }
+      \or: \zhnum_output:n { thu }
+      \or: \zhnum_output:n { fri }
     \fi:
   }
 \cs_new:Npn \zhnum_Zeller:nnn #1#2#3
@@ -457,13 +506,16 @@
       }
       { 7 }
   }
+\zhnum_expand_wrap:wn
 \cs_new:Npn \zhtime #1
   { \__zhnum_time:ww #1 \q_stop }
-\use:x
+\use:e
   {
-    \cs_new:Npn \exp_not:N \__zhnum_time:ww ##1 \c_colon_str ##2 \exp_not:N \q_stop
+    \cs_new:Npn \exp_not:N \__zhnum_time:ww
+      #1 \c_colon_str #2 \exp_not:N \q_stop
   }
   { \__zhnum_time_aux:nn {#1} {#2} }
+\zhnum_expand_wrap:wn
 \cs_new:Npn \zhcurrtime
   {
     \__zhnum_time_aux:nn
@@ -478,14 +530,13 @@
   }
 \cs_new:Npn \__zhnum_time_aux:Nnnn #1#2#3#4
   {
-    #1 {#3} #2 \c__zhnum_hour_tl #2
-    #1 {#4} #2 \c__zhnum_minute_tl
+    #1 {#3} #2 \zhnum_output:n { hour } #2
+    #1 {#4} #2 \zhnum_output:n { minute }
   }
-\cs_new:Npn \zhnum_digit_map:n #1
-  { \use:c { c__zhnum_ #1 _tl } }
 \cs_new:Npn \zhnum_scale_map:n #1
   {
-    \cs_if_exist_use:cF { c__zhnum_s #1 _tl }
+    \tl_if_exist:cTF { l__zhnum_s #1 _tl }
+      { \zhnum_output:n { s #1 } }
       { \zhnum_scale_map_hook:n {#1} }
   }
 \cs_new:Npn \zhnum_scale_map_loop:n #1
@@ -494,33 +545,47 @@
 \int_new:N \l__zhnum_scale_int
 \int_set:Nn \l__zhnum_scale_int { 11 }
 \cs_new_eq:NN \zhnum_scale_map_hook:n \zhnum_scale_map_loop:n
-\tl_const:cn { c__zhnum_s0_tl } { }
+\tl_new:c { l__zhnum_s 0 _tl }
 \NewDocumentCommand \zhnumExtendScaleMap { > { \TrimSpaces } +o +m }
   {
-    \int_zero:N \l_tmpa_int
+    \int_zero:N \l__zhnum_tmp_int
     \clist_map_function:nN {#2} \zhnum_set_scale:n
-    \IfNoValueF {#1}
+    \tl_if_novalue:nF {#1}
       { \cs_set:Npn \zhnum_scale_map_hook:n ##1 {#1} }
   }
 \cs_new_protected:Npn \zhnum_set_scale:n #1
   {
-    \int_incr:N \l_tmpa_int
-    \tl_set:Nx \l_tmpa_tl
-      { c__zhnum_s \int_eval:n { \l_tmpa_int + 11 } _tl }
-    \tl_if_exist:cF { \l_tmpa_tl }
-      { \int_incr:N \l__zhnum_scale_int }
-    \tl_set:cn { \l_tmpa_tl } {#1}
+    \int_incr:N \l__zhnum_tmp_int
+    \exp_args:Nc \__zhnum_set_scale:Nn
+      { l__zhnum_s \int_eval:n { \l__zhnum_tmp_int + 11 } _tl }
+      {#1}
   }
+\cs_new_protected:Npn \__zhnum_set_scale:Nn #1
+  {
+    \tl_if_exist:NF #1
+      {
+        \tl_new:N #1
+        \int_incr:N \l__zhnum_scale_int
+      }
+    \tl_set:Nn #1
+  }
+\int_new:N \l__zhnum_tmp_int
+\zhnum_expand_wrap:wn
 \cs_new:Npn \zhnum_ganzhi_normal:nnn #1#2#3
   {
     \int_compare:nNnF {#1} < \c_one_int
-      { \cs_if_exist_use:c { c__zhnum_ #2 _ #1 _tl } }
+      {
+        \cs_if_free:cF { l__zhnum_ #2 _ #1 _tl }
+          { \zhnum_output:n { #2 _ #1 } }
+      }
   }
+\zhnum_expand_wrap:wn
 \cs_new:Npn \zhnum_ganzhi_cyclic:nnn #1#2#3
   {
     \int_compare:nNnF {#1} = \c_zero_int
       {
-        \cs_if_exist_use:cF { c__zhnum_ #2 _ #1 _tl }
+        \tl_if_exist:cTF { l__zhnum_ #2 _ #1 _tl }
+          { \zhnum_output:n { #2 _ #1 } }
           {
             \__zhnum_ganzhi_cyclic_mod:fnnn
               { \int_mod:nn {#1} {#3} } {#1} {#2} {#3}
@@ -530,11 +595,11 @@
 \cs_new:Npn \__zhnum_ganzhi_cyclic_mod:nnnn #1#2#3#4
   {
     \int_compare:nNnTF {#2} > \c_zero_int
-      { \use:c { c__zhnum_ #3 _ #1 _tl } }
+      { \zhnum_output:n { #3 _ #1 } }
       {
         \int_compare:nNnTF {#1} = \c_zero_int
-          { \use:c { c__zhnum_ #3 _ 1 _tl } }
-          { \use:c { c__zhnum_ #3 _ \int_eval:n {  #1 + #4 + 1 } _tl } }
+          { \zhnum_output:n { #3 _ 1 } }
+          { \zhnum_output:n { #3 _ \int_eval:n {  #1 + #4 + 1 } } }
       }
   }
 \cs_generate_variant:Nn \__zhnum_ganzhi_cyclic_mod:nnnn { f }
@@ -548,102 +613,136 @@
   { \zhnum_ganzhi:fnn { \int_eval:n {#1} } { ganzhi } { 60 } }
 \cs_new:Npn \zhganzhinian #1
   { \zhnum_ganzhi_nian:f { \int_eval:n {#1} } }
+\zhnum_expand_wrap:wn
 \cs_new:Npn \zhnum_ganzhi_nian:n #1
   {
     \int_compare:nNnTF {#1} > \c_zero_int
-      { \use:c { c__zhnum_ganzhi_ \int_mod:nn { #1 + 57 } { 60 } _tl } }
+      { \zhnum_output:n { ganzhi_ \int_mod:nn { #1 + 57 } { 60 } } }
       {
         \int_compare:nNnF {#1} = \c_zero_int
           {
-            \use:c
+            \zhnum_output:n
               {
-                c__zhnum_ganzhi_
-                  \int_eval:n { \int_mod:nn { #1 - 2 } { 60 } + 60 }
-                _tl
+                ganzhi_ \int_eval:n
+                  { \int_mod:nn { #1 - 2 } { 60 } + 60 }
               }
           }
       }
   }
 \cs_generate_variant:Nn \zhnum_ganzhi_nian:n { f }
+\tl_new:N \l__zhnum_kv_tl
+\tl_new:N \l__zhnum_tmp_tl
 \group_begin:
-  \tl_set:Nn \l_tmpa_tl
-    {
-      -   .tl_set:N = \l__zhnum_minus_tl ,
-      -0  .tl_set:N = \l__zhnum_null_tl ,
-    }
-  \tl_put_right:Nx \l_tmpa_tl
-    {
-      E2  .tl_set:N = \exp_not:c { l__zhnum_ 100 _tl } ,
-      E3  .tl_set:N = \exp_not:c { l__zhnum_ 1000 _tl } ,
-      FE2 .tl_set:N = \exp_not:c { l__zhnum_financial_ 100 _tl } ,
-      FE3 .tl_set:N = \exp_not:c { l__zhnum_financial_ 1000 _tl } ,
-      D11 .tl_set:N = \exp_not:c { l__zhnum_dizhi_ 11 _tl } ,
-      D12 .tl_set:N = \exp_not:c { l__zhnum_dizhi_ 12 _tl } ,
-      E44 .tl_set:N = \exp_not:c { l__zhnum_ s11 _tl } ,
-    }
+  \tl_build_begin:N \l__zhnum_kv_tl
   \int_step_inline:nn { 10 }
     {
-      \tl_put_right:Nx \l_tmpa_tl
+      \tl_new:c { l__zhnum_ #1 _tl }
+      \tl_build_put_right:Nx \l__zhnum_kv_tl
         {
-            #1 .tl_set:N = \exp_not:c { l__zhnum_ #1 _tl } ,
+            #1 .tl_set:N = \exp_not:c { l__zhnum_normal_    #1 _tl } ,
            F#1 .tl_set:N = \exp_not:c { l__zhnum_financial_ #1 _tl } ,
-           T#1 .tl_set:N = \exp_not:c { l__zhnum_tiangan_ #1 _tl } ,
-           D#1 .tl_set:N = \exp_not:c { l__zhnum_dizhi_ #1 _tl } ,
-          GZ#1 .tl_set:N = \exp_not:c { l__zhnum_ganzhi_ #1 _tl } ,
           E \int_eval:n { #1 * 4 }
                .tl_set:N = \exp_not:c { l__zhnum_ s#1 _tl } ,
         }
     }
-  \int_step_inline:nnn { 11 } { 60 }
-    {
-      \tl_put_right:Nx \l_tmpa_tl
-        { GZ#1 .tl_set:N = \exp_not:c { l__zhnum_ganzhi_ #1 _tl } , }
-    }
   \clist_map_inline:nn { 0 , 100 , 1000 }
     {
-      \tl_put_right:Nx \l_tmpa_tl
+      \tl_new:c { l__zhnum_ #1 _tl }
+      \tl_build_put_right:Nx \l__zhnum_kv_tl
         {
-           #1 .tl_set:N = \exp_not:c { l__zhnum_ #1 _tl } ,
+           #1 .tl_set:N = \exp_not:c { l__zhnum_normal_    #1 _tl } ,
           F#1 .tl_set:N = \exp_not:c { l__zhnum_financial_ #1 _tl } ,
         }
     }
-  \clist_map_inline:nn { 20 , 30 , 40 , 200 }
+  \clist_map_inline:nn
     {
-      \tl_put_right:Nx \l_tmpa_tl
+      20 , 30 , 40 , 200 ,
+      dot , and , parts , year , month , day , hour , minute
+    }
+    {
+      \tl_build_put_right:Nx \l__zhnum_kv_tl
         { #1 .tl_set:N = \exp_not:c { l__zhnum_ #1 _tl } , }
     }
+  \tl_build_put_right:Nx \l__zhnum_kv_tl
+    {
+      -   .tl_set:N = \exp_not:N \l__zhnum_minus_tl ,
+      -0  .tl_set:N = \exp_not:N \l__zhnum_null_tl ,
+      E2  .tl_set:N = \exp_not:c { l__zhnum_normal_     100 _tl } ,
+      E3  .tl_set:N = \exp_not:c { l__zhnum_normal_    1000 _tl } ,
+      FE2 .tl_set:N = \exp_not:c { l__zhnum_financial_  100 _tl } ,
+      FE3 .tl_set:N = \exp_not:c { l__zhnum_financial_ 1000 _tl } ,
+      E44 .tl_set:N = \exp_not:c { l__zhnum_ s11 _tl }
+    }
+  \tl_build_get:NN \l__zhnum_kv_tl \l__zhnum_tmp_tl
+  \cs_set:Npn \__zhnum_tmp:w #1 . #2 \q_stop
+    { , #1 .groups:n = { user } }
+  \clist_map_inline:Nn \l__zhnum_tmp_tl
+    {
+      \tl_build_put_right:Nx \l__zhnum_kv_tl
+        { \__zhnum_tmp:w #1 \q_stop }
+    }
+  \tl_build_put_right:Nn \l__zhnum_kv_tl
+    {
+      ,
+      weekday .tl_set:N = \l__zhnum_weekday_tl ,
+      weekday .groups:n = { user , pre , weekday } ,
+    }
   \clist_map_inline:nn
+    { mon , tue , wed , thu , fri , sat , sun }
     {
-      dot , and , parts , year , month , day , weekday , hour , minute
-      mon , tue , wed , thu , fri , sat , sun
+      \tl_build_put_right:Nx \l__zhnum_kv_tl
+        {
+          #1 .tl_set:N = \exp_not:c { l__zhnum_ #1 _tl } ,
+          #1 .groups:n = { user , pos , day } ,
+        }
     }
+  \int_step_inline:nn { 10 }
     {
-      \tl_put_right:Nx \l_tmpa_tl
-        { #1 .tl_set:N = \exp_not:c { l__zhnum_ #1 _tl } , }
+      \tl_build_put_right:Nx \l__zhnum_kv_tl
+        {
+          T#1 .tl_set:N = \exp_not:c { l__zhnum_ganzhi_ #1 _tl } ,
+          T#1 .groups:n = { user , pre , tiandi } ,
+        }
     }
-\use:x
-  {
-    \group_end:
-    \keys_define:nn { zhnum / options } { \exp_not:o \l_tmpa_tl }
-  }
-\cs_new_protected:Npn \zhnum_set_digits_map:nn #1#2
-  { \prop_put:Nnn \l__zhnum_cfg_map_prop {#1} {#2} }
+  \int_step_inline:nn { 12 }
+    {
+      \tl_build_put_right:Nx \l__zhnum_kv_tl
+        {
+          D#1 .tl_set:N = \exp_not:c { l__zhnum_dizhi_ #1 _tl } ,
+          D#1 .groups:n = { user , pre , tiandi } ,
+        }
+    }
+  \int_step_inline:nn { 60 }
+    {
+      \tl_build_put_right:Nx \l__zhnum_kv_tl
+        {
+          GZ#1 .tl_set:N = \exp_not:c { l__zhnum_ganzhi_ #1 _tl } ,
+          GZ#1 .groups:n = { user , pos , ganzhi } ,
+        }
+    }
+  \tl_build_end:N \l__zhnum_kv_tl
+  \exp_args:NNno \group_end:
+\keys_define:nn
+  { zhnum / options }
+  { \l__zhnum_kv_tl }
+\cs_new_protected:Npn \zhnum_set_digits_map:nn #1
+  { \prop_put:Nnn \l__zhnum_cfg_map_prop {#1} }
 \cs_new_protected:Npn \zhnum_set_digits_map:nnn #1#2#3
   {
     \prop_put_if_new:Nnn \l__zhnum_cfg_map_prop {#1} {#3}
     \prop_put:Nnn \l__zhnum_cfg_map_var_prop {#1_#2} {#3}
   }
-\cs_new_protected:Npn \zhnum_set_financial_map:nn #1#2
-  { \prop_put:Nnn \l__zhnum_cfg_map_finan_prop {#1} {#2} }
+\cs_new_protected:Npn \zhnum_set_financial_map:nn #1
+  { \prop_put:Nnn \l__zhnum_cfg_map_finan_prop {#1} }
 \cs_new_protected:Npn \zhnum_set_financial_map:nnn #1#2#3
   {
     \prop_put_if_new:Nnn \l__zhnum_cfg_map_finan_prop {#1} {#3}
     \prop_put:Nnn \l__zhnum_cfg_map_var_prop { financial_#1_#2 } {#3}
   }
-\cs_new_protected:Npn \zhnum_set_tiangan_map:nn #1#2
-  { \prop_put:Nnn \l__zhnum_cfg_map_ganzhi_prop { tiangan_#1 } {#2} }
-\cs_new_protected:Npn \zhnum_set_dizhi_map:nn #1#2
-  { \prop_put:Nnn \l__zhnum_cfg_map_ganzhi_prop { dizhi_#1 } {#2} }
+\cs_new_protected:Npn \zhnum_set_tiangan_map:nn #1
+  { \prop_put:Nnn \l__zhnum_cfg_map_ganzhi_prop { tiangan_#1 } }
+\cs_new_protected:Npn \zhnum_set_dizhi_map:nn #1
+  { \prop_put:Nnn \l__zhnum_cfg_map_ganzhi_prop { dizhi_#1 } }
 \prop_new:N \l__zhnum_cfg_map_prop
 \prop_new:N \l__zhnum_cfg_map_var_prop
 \prop_new:N \l__zhnum_cfg_map_finan_prop
@@ -650,158 +749,282 @@
 \prop_new:N \l__zhnum_cfg_map_ganzhi_prop
 \cs_new_protected:Npn \zhnum_parse_config:
   {
+    \tl_clear_new:N \l__zhnum_reset_tl
+    \tl_clear_new:N \l__zhnum_reset_simp_tl
+    \tl_clear_new:N \l__zhnum_reset_trad_tl
+    \tl_clear_new:N \l__zhnum_set_ancient_tl
+    \tl_clear_new:N \l__zhnum_set_normal_tl
+    \tl_clear_new:N \l__zhnum_reset_ancient_tl
+    \tl_clear_new:N \l__zhnum_reset_normal_tl
+    \tl_clear_new:N \l__zhnum_reset_financial_tl
     \prop_map_function:NN \l__zhnum_cfg_map_prop \zhnum_check_simp:nn
-    \prop_map_function:NN \l__zhnum_cfg_map_ganzhi_prop \zhnum_assgin_ganzhi:nn
-    \zhnum_set_zero:
-    \zhnum_set_week_day:
-    \bool_if:NF \l__zhnum_reset_bool
-      {
-        \zhnum_assgin_const:
-        \bool_set_true:N \l__zhnum_reset_bool
-      }
+    \zhnum_set_ganzhi:
+    \zhnum_reset_all:
   }
 \cs_new_protected:Npn \zhnum_check_simp:nn #1#2
   {
-    \__zhnum_check_simp_aux:nn {#2} {#1}
-    \prop_get:NnNT \l__zhnum_cfg_map_finan_prop {#1} \l_tmpa_tl
-      { \exp_args:No \__zhnum_check_simp_aux:nn { \l_tmpa_tl } { financial_ #1 } }
+    \prop_get:NnNTF \l__zhnum_cfg_map_var_prop
+      { #1_ancient } \l__zhnum_ancient_tl
+      { \__zhnum_add_reset_ancient:nN {#1} \l__zhnum_ancient_tl }
+      {
+        \__zhnum_check_simp_aux:nn {#2} {#1}
+        \prop_get:NnNT \l__zhnum_cfg_map_finan_prop {#1} \l__zhnum_tmp_tl
+          {
+            \exp_args:No \__zhnum_check_simp_aux:nn
+              { \l__zhnum_tmp_tl } { financial_ #1 }
+            \__zhnum_add_reset_financial:n {#1}
+          }
+      }
   }
 \cs_new_protected:Npn \__zhnum_check_simp_aux:nn #1#2
   {
-    \prop_get:NnNTF \l__zhnum_cfg_map_var_prop { #2 _trad } \l_tmpa_tl
+    \prop_get:NnNTF \l__zhnum_cfg_map_var_prop
+      { #2 _trad } \l__zhnum_trad_tl
       {
-        \prop_get:NnNF \l__zhnum_cfg_map_var_prop { #2 _simp } \l_tmpb_tl
-          { \tl_set:Nn \l_tmpb_tl {#1} }
-        \tl_set:cx { l__zhnum_ #2 _tl }
-          {
-            \exp_not:n { \bool_if:NTF \l__zhnum_simp_bool }
-              { \exp_not:o \l_tmpb_tl } { \exp_not:o \l_tmpa_tl }
-          }
+        \prop_get:NnNF \l__zhnum_cfg_map_var_prop
+          { #2 _simp } \l__zhnum_simp_tl
+          { \tl_set:Nn \l__zhnum_simp_tl {#1} }
+        \__zhnum_add_reset_simp:nNN
+          {#2} \l__zhnum_simp_tl \l__zhnum_trad_tl
       }
-      { \tl_set:cn { l__zhnum_ #2 _tl } {#1} }
+      { \__zhnum_add_reset:nn {#2} {#1} }
   }
-\cs_new_protected:Npn \zhnum_assgin_const:
+\tl_new:N \l__zhnum_simp_tl
+\tl_new:N \l__zhnum_trad_tl
+\tl_new:N \l__zhnum_ancient_tl
+\cs_new_protected:Npn \__zhnum_add_reset:nn #1#2
   {
-    \prop_map_function:NN \l__zhnum_cfg_map_prop \zhnum_check_financial:nn
-    \zhnum_set_alias:
+    \tl_put_right:Nx \l__zhnum_reset_tl
+      {
+        \tl_set:Nn \exp_not:c { l__zhnum_ #1 _tl }
+          { \exp_not:n {#2} }
+      }
   }
-\cs_new_protected:Npn \zhnum_check_financial:nn #1#2
+\cs_new_protected:Npn \__zhnum_add_reset_simp:nNN #1#2#3
   {
-    \prop_get:NnNTF \l__zhnum_cfg_map_finan_prop {#1} \l_tmpa_tl
+    \tl_put_right:Nx \l__zhnum_reset_simp_tl
       {
-        \zhnum_assgin_const_tl:cx { c__zhnum_ #1 _tl }
-          {
-            \exp_not:n { \bool_if:NTF \l__zhnum_normal_bool }
-              { \exp_not:c { l__zhnum_ #1 _tl } }
-              { \exp_not:c { l__zhnum_financial_ #1 _tl } }
-          }
+        \tl_set:Nn \exp_not:c { l__zhnum_ #1 _tl }
+          { \exp_not:o {#2} }
       }
+    \tl_put_right:Nx \l__zhnum_reset_trad_tl
       {
-        \zhnum_assgin_const_tl:cx
-          { c__zhnum_ #1 _tl } { \exp_not:c { l__zhnum_ #1 _tl } }
+        \tl_set:Nn \exp_not:c { l__zhnum_ #1 _tl }
+          { \exp_not:o {#3} }
       }
   }
-\cs_new_protected:Npn \zhnum_set_zero:
+\cs_new_protected:Npn \__zhnum_add_reset_financial:n #1
   {
-    \tl_set:cx { l__zhnum_0_tl }
+    \tl_put_right:Nx \l__zhnum_set_normal_tl
       {
-        \exp_not:n { \bool_if:NTF \l__zhnum_null_bool }
-          { \exp_not:o \l__zhnum_null_tl } { \exp_not:v { l__zhnum_0_tl } }
+        \tl_set_eq:NN
+          \exp_not:c { l__zhnum_normal_ #1 _tl }
+          \exp_not:c { l__zhnum_ #1 _tl }
       }
+    \tl_put_right:Nx \l__zhnum_reset_normal_tl
+      {
+        \tl_set_eq:NN
+          \exp_not:c { l__zhnum_ #1 _tl }
+          \exp_not:c { l__zhnum_normal_ #1 _tl }
+      }
+    \tl_put_right:Nx \l__zhnum_reset_financial_tl
+      {
+        \tl_set_eq:NN
+          \exp_not:c { l__zhnum_ #1 _tl }
+          \exp_not:c { l__zhnum_financial_ #1 _tl }
+      }
   }
+\cs_new_protected:Npn \__zhnum_add_reset_ancient:nN #1#2
+  {
+    \tl_put_right:Nx \l__zhnum_reset_ancient_tl
+      {
+        \tl_set:Nn \exp_not:c { l__zhnum_ #1 _tl }
+          { \exp_not:o {#2} }
+      }
+    \tl_put_right:Nx \l__zhnum_set_ancient_tl
+      {
+        \tl_concat:NNN
+          \exp_not:c { l__zhnum_ #1 _tl }
+          \exp_not:c { l__zhnum_   \str_head:n {#1} _tl }
+          \exp_not:c { l__zhnum_ 1 \str_tail:n {#1} _tl }
+      }
+  }
 \cs_new_protected:Npn \zhnum_set_week_day:
   {
-    \tl_set:Nx \l__zhnum_mon_tl
-      { \exp_not:N \c__zhnum_weekday_tl \exp_not:v { l__zhnum_1_tl } }
-    \tl_set:Nx \l__zhnum_tue_tl
-      { \exp_not:N \c__zhnum_weekday_tl \exp_not:v { l__zhnum_2_tl } }
-    \tl_set:Nx \l__zhnum_wed_tl
-      { \exp_not:N \c__zhnum_weekday_tl \exp_not:v { l__zhnum_3_tl } }
-    \tl_set:Nx \l__zhnum_thu_tl
-      { \exp_not:N \c__zhnum_weekday_tl \exp_not:v { l__zhnum_4_tl } }
-    \tl_set:Nx \l__zhnum_fri_tl
-      { \exp_not:N \c__zhnum_weekday_tl \exp_not:v { l__zhnum_5_tl } }
-    \tl_set:Nx \l__zhnum_sat_tl
-      { \exp_not:N \c__zhnum_weekday_tl \exp_not:v { l__zhnum_6_tl } }
-    \tl_set:Nx \l__zhnum_sun_tl
-      { \exp_not:N \c__zhnum_weekday_tl \exp_not:o \l__zhnum_day_tl }
+    \cs_set_protected:Npx \zhnum_reset_week_day:
+      {
+        \__zhnum_set_week_day:nn { mon } { 1 }
+        \__zhnum_set_week_day:nn { tue } { 2 }
+        \__zhnum_set_week_day:nn { wed } { 3 }
+        \__zhnum_set_week_day:nn { thu } { 4 }
+        \__zhnum_set_week_day:nn { fri } { 5 }
+        \__zhnum_set_week_day:nn { sat } { 6 }
+        \__zhnum_set_week_day:nn { sun } { day }
+      }
   }
-\clist_map_inline:nn { mon , tue , wed , thu , fri , sat , sun }
-  { \tl_const:cx { c__zhnum_ #1 _tl } { \exp_not:c { l__zhnum_ #1 _tl } } }
-\cs_new_protected:Npn \zhnum_assgin_ganzhi:nn #1#2
+\cs_new_eq:NN \zhnum_reset_week_day: \prg_do_nothing:
+\cs_new:Npn \__zhnum_set_week_day:nn #1#2
+  {
+    \tl_set:Nx \exp_not:c { l__zhnum_ #1 _tl }
+      {
+        \exp_not:N \exp_not:o { \exp_not:N \l__zhnum_weekday_tl }
+        \exp_not:N \exp_not:n { \exp_not:v { l__zhnum_ #2 _tl } }
+      }
+  }
+\cs_new_protected:Npn \zhnum_set_ganzhi:
+  {
+    \prop_map_function:NN
+      \l__zhnum_cfg_map_ganzhi_prop
+      \__zhnum_add_reset:nn
+  }
+\cs_new_protected:Npn \__zhnum_reset_ganzhi:nn #1#2
   { \tl_set:cn { l__zhnum_ #1 _tl } {#2} }
 \cs_new:Npn \zhnum_zero_mod:nn #1#2
   { \exp_args:Nf \__zhnum_zero_mod_aux:nn { \int_mod:nn {#1} {#2} } {#2} }
 \cs_new:Npn \__zhnum_zero_mod_aux:nn #1#2
   { \int_compare:nNnTF {#1} = \c_zero_int {#2} {#1} }
-\int_step_inline:nn { 60 }
+\tl_new:c { l__zhnum_dizhi_ 0 _tl }
+\tl_new:c { l__zhnum_ganzhi_ 0 _tl }
+\tl_new:c { l__zhnum_tiangan_ 0 _tl }
+\group_begin:
+\cs_set:Npn \__zhnum_tmp:w #1
   {
-    \tl_const:cx { c__zhnum_ganzhi_ #1 _tl } { \exp_not:c { l__zhnum_ganzhi_ #1 _tl } }
-    \tl_set:cx { l__zhnum_ganzhi_ #1 _tl }
+    \tl_concat:NNN
+      \exp_not:c { l__zhnum_ganzhi_ #1 _tl }
+      \exp_not:c { l__zhnum_tiangan_ \zhnum_zero_mod:nn {#1} { 10 } _tl }
+      \exp_not:c { l__zhnum_dizhi_   \zhnum_zero_mod:nn {#1} { 12 } _tl }
+  }
+\cs_new_protected:Npx \zhnum_reset_ganzhi:
+  {
+    \tl_set_eq:NN
+      \exp_not:c { l__zhnum_dizhi_ 0 _tl }
+      \exp_not:c { l__zhnum_dizhi_ 12 _tl }
+    \tl_set_eq:NN
+      \exp_not:c { l__zhnum_tiangan_ 0 _tl }
+      \exp_not:c { l__zhnum_tiangan_ 10 _tl }
+    \int_step_function:nN { 60 } \__zhnum_tmp:w
+    \tl_set_eq:NN
+      \exp_not:c { l__zhnum_ganzhi_ 0 _tl }
+      \exp_not:c { l__zhnum_ganzhi_ 60 _tl }
+  }
+\group_end:
+\cs_new_protected:Npn \zhnum_reset_config:
+  { \zhnum_load_cfg:o { \l__zhnum_encoding_str } }
+\cs_new_protected:Npn \zhnum_reset_all:
+  {
+    \zhnum_reset_main:
+    \zhnum_reset_simp:
+    \zhnum_set_week_day:
+    \zhnum_reset_week_day:
+    \zhnum_reset_ganzhi:
+    \zhnum_reset_normal:
+  }
+\cs_new_protected:Npn \zhnum_reset_main:
+  {
+    \tl_use:N \l__zhnum_reset_tl
+    \tl_use:N \l__zhnum_set_normal_tl
+    \tl_concat:NNN
+      \l__zhnum_reset_normal_tl
+      \l__zhnum_reset_normal_tl
+      \c__zhnum_set_zero_tl
+    \tl_concat:NNN
+      \l__zhnum_reset_financial_tl
+      \l__zhnum_reset_financial_tl
+      \c__zhnum_set_zero_tl
+    \tl_concat:NNN
+      \l__zhnum_reset_financial_tl
+      \l__zhnum_reset_financial_tl
+      \l__zhnum_set_ancient_tl
+  }
+\tl_const:Nx \c__zhnum_set_zero_tl
+  {
+    \tl_set_eq:NN
+      \exp_not:N \l__zhnum_zero_tl
+      \exp_not:c { l__zhnum_0_tl }
+  }
+\tl_new:N \l__zhnum_zero_tl
+\cs_new_protected:Npn \zhnum_reset_style:
+  {
+    \zhnum_reset_simp:
+    \zhnum_reset_normal:
+  }
+\cs_new_protected:Npn \zhnum_reset_simp:
+  {
+    \bool_if:NTF \l__zhnum_simp_bool
+      { \tl_use:N \l__zhnum_reset_simp_tl }
+      { \tl_use:N \l__zhnum_reset_trad_tl }
+  }
+\cs_new_protected:Npn \zhnum_reset_normal:
+  {
+    \bool_if:NTF \l__zhnum_normal_bool
       {
-        \exp_not:c { l__zhnum_tiangan_ \zhnum_zero_mod:nn {#1} { 10 } _tl }
-        \exp_not:c { l__zhnum_dizhi_ \zhnum_zero_mod:nn {#1} { 12 } _tl }
+        \tl_use:N \l__zhnum_reset_normal_tl
+        \__zhnum_reset_ancient:
+        \__zhnum_reset_zero:
       }
+      { \tl_use:N \l__zhnum_reset_financial_tl }
   }
-\cs_new_eq:cc { c__zhnum_ganzhi_ 0 _tl } { c__zhnum_ganzhi_ 60 _tl }
-\cs_new_eq:NN \zhnum_assgin_const_tl:cx \tl_const:cx
-\AtEndOfPackage
+\cs_new_protected:Npn \__zhnum_reset_ancient:
   {
-    \prop_map_inline:Nn \l__zhnum_cfg_map_ganzhi_prop
-      { \tl_const:cx { c__zhnum_ #1 _tl } { \exp_not:c { l__zhnum_ #1 _tl } } }
-    \cs_new_eq:cc { c__zhnum_tiangan_ 0 _tl } { c__zhnum_tiangan_ 10 _tl }
-    \cs_new_eq:cc { c__zhnum_dizhi_ 0 _tl }   { c__zhnum_dizhi_ 12 _tl }
-    \cs_set_eq:NN \zhnum_assgin_const_tl:cx \tl_set:cx
+    \bool_if:NTF \l__zhnum_ancient_bool
+      { \tl_use:N \l__zhnum_reset_ancient_tl }
+      { \tl_use:N \l__zhnum_set_ancient_tl }
   }
-\cs_new_eq:NN \zhnum_set_alias:NN \cs_new_eq:NN
-\cs_new_protected:Npx \zhnum_set_alias:
+\cs_new_protected:Npx \__zhnum_reset_zero:
   {
-    \zhnum_set_alias:NN \exp_not:N \c__zhnum_zero_tl
-                        \exp_not:c { c__zhnum_ 0 _tl }
-    \zhnum_set_alias:NN \exp_not:N \c__zhnum_ten_tl
-                        \exp_not:c { c__zhnum_ 10 _tl }
-    \zhnum_set_alias:NN \exp_not:N \c__zhnum_hundred_tl
-                        \exp_not:c { c__zhnum_ 100 _tl }
-    \zhnum_set_alias:NN \exp_not:N \c__zhnum_thousand_tl
-                        \exp_not:c { c__zhnum_ 1000 _tl }
+    \exp_not:n { \bool_if:NT \l__zhnum_null_bool }
+      {
+        \tl_set_eq:NN
+          \exp_not:c { l__zhnum_0_tl }
+          \exp_not:N \l__zhnum_null_tl
+      }
   }
-\AtEndOfPackage
-  { \cs_set_eq:NN \zhnum_set_alias:NN \tl_set_eq:NN }
 \cs_new_protected:Npn \zhnum_load_cfg:n #1
   {
     \zhnum_set_cfg_name:Nn \l__zhnum_cfg_str {#1}
-    \str_if_eq:NNF \l__zhnum_cfg_str \l__zhnum_last_cfg_str
-      { \zhnum_update_cfg:n {#1} }
-    \zhnum_parse_config:
+    \str_if_eq:NNTF \l__zhnum_cfg_str \l__zhnum_last_cfg_str
+      { \zhnum_reset_all: }
+      {
+        \zhnum_update_cfg:n {#1}
+        \zhnum_parse_config:
+      }
   }
 \cs_generate_variant:Nn \zhnum_load_cfg:n { o }
 \cs_new_protected:Npn \zhnum_update_cfg:n #1
   {
     \prop_if_exist:cTF { g__zhnum_cfg_ \l__zhnum_cfg_str _prop }
-      { \str_set_eq:NN \l__zhnum_last_cfg_str \l__zhnum_cfg_str }
+      { \__zhnum_set_cfg_prop: }
       { \zhnum_input_cfg:n {#1} }
+  }
+\cs_new_protected:Npn \__zhnum_set_cfg_prop:
+  {
+    \str_set_eq:NN \l__zhnum_last_cfg_str \l__zhnum_cfg_str
     \__zhnum_update_cfg_prop:N \prop_set_eq:Nc
   }
 \cs_new_protected:Npn \zhnum_input_cfg:n #1
   {
-    \file_if_exist:nTF { zhnumber - #1 .cfg }
+    \file_get_full_name:nNTF { zhnumber - #1 .cfg } \l__zhnum_cfg_file_tl
       {
         \bool_set_false:N \l__zhnum_reset_bool
         \__zhnum_update_cfg_prop:N \__zhnum_prop_initial:Nn
         \group_begin:
           \zhnum_set_catcode:
-          \file_input:n { zhnumber - #1 .cfg }
+          \exp_args:No \file_input:n { \l__zhnum_cfg_file_tl }
           \__zhnum_update_cfg_prop:N \__zhnum_prop_gset_eq:Nn
         \group_end:
+        \__zhnum_set_cfg_prop:
       }
       { \msg_error:nnx { zhnumber } { file-not-found } {#1} }
   }
-\cs_new_protected:Npn \__zhnum_update_cfg_prop:N #1
+\tl_new:N \l__zhnum_cfg_file_tl
+\cs_new_protected:Npn \__zhnum_update_cfg_prop:N
+  { \exp_args:No \__zhnum_update_cfg_prop_aux:nN { \l__zhnum_cfg_str } }
+\cs_new_protected:Npn \__zhnum_update_cfg_prop_aux:nN #1#2
   {
-    #1 \l__zhnum_cfg_map_prop        { g__zhnum_cfg_ \l__zhnum_cfg_str _prop }
-    #1 \l__zhnum_cfg_map_var_prop    { g__zhnum_cfg_var_ \l__zhnum_cfg_str _prop }
-    #1 \l__zhnum_cfg_map_finan_prop  { g__zhnum_cfg_finan_ \l__zhnum_cfg_str _prop }
-    #1 \l__zhnum_cfg_map_ganzhi_prop { g__zhnum_cfg_ganzhi_ \l__zhnum_cfg_str _prop }
+    #2 \l__zhnum_cfg_map_prop        { g__zhnum_cfg_        #1 _prop }
+    #2 \l__zhnum_cfg_map_var_prop    { g__zhnum_cfg_var_    #1 _prop }
+    #2 \l__zhnum_cfg_map_finan_prop  { g__zhnum_cfg_finan_  #1 _prop }
+    #2 \l__zhnum_cfg_map_ganzhi_prop { g__zhnum_cfg_ganzhi_ #1 _prop }
   }
 \cs_new_protected:Npn \__zhnum_prop_initial:Nn #1#2
   {
@@ -819,72 +1042,67 @@
     The~requested~file~could~not~be~found~in~the~current~directory,~
     in~the~TeX~search~path~or~in~the~LaTeX~search~path.
   }
-\bool_lazy_any:nTF
+\bool_const:Nn \c__zhnum_unicode_engine_bool
   {
-    { \sys_if_engine_xetex_p:  }
-    { \sys_if_engine_luatex_p: }
-    { \sys_if_engine_uptex_p: }
+    \bool_lazy_any_p:n
+      {
+        { \sys_if_engine_xetex_p:  }
+        { \sys_if_engine_luatex_p: }
+        { \sys_if_engine_uptex_p: }
+      }
   }
+\bool_if:NTF \c__zhnum_unicode_engine_bool
   {
-    \cs_new_eq:NN \zhnum_if_unicode_engine_p: \c_true_bool
-    \cs_new_eq:NN \zhnum_if_unicode_engine:TF \use_i:nn
+    \cs_new_eq:NN \zhnum_set_catcode: \prg_do_nothing:
+    \cs_new_protected:Npn \zhnum_set_cfg_name:Nn #1#2
+      {
+        \str_set:Nx \l__zhnum_encoding_str {#2}
+        \str_set_eq:NN #1 \l__zhnum_encoding_str
+      }
   }
   {
-    \cs_new_eq:NN \zhnum_if_unicode_engine_p: \c_false_bool
-    \cs_new_eq:NN \zhnum_if_unicode_engine:TF \use_ii:nn
+    \cs_new_protected:Npn \zhnum_set_catcode:
+      {
+        \bool_if:NTF \l__zhnum_active_char_bool
+          { \zhnum_set_active: }
+          { \zhnum_set_other: }
+      }
+    \cs_new_protected:Npx \zhnum_set_active:
+      {
+        \int_step_function:nnN
+          { 128 } { 255 } \char_set_catcode_active:n
+      }
+    \cs_new_protected:Npx \zhnum_set_other:
+      {
+        \int_step_function:nnN
+          { 128 } { 255 } \char_set_catcode_other:n
+      }
+    \cs_new_protected:Npn \zhnum_set_cfg_name:Nn #1#2
+      {
+        \str_set:Nx \l__zhnum_encoding_str {#2}
+        \str_set:Nx #1
+          {
+            \l__zhnum_encoding_str
+            \bool_if:NTF \l__zhnum_active_char_bool
+              { / active }
+              { / other }
+          }
+      }
+    \bool_new:N \l__zhnum_active_char_bool
+    \bool_set_true:N \l__zhnum_active_char_bool
   }
-\if_predicate:w \zhnum_if_unicode_engine_p:
-  \cs_new_eq:NN \zhnum_set_catcode: \prg_do_nothing:
-  \cs_new_protected:Npn \zhnum_set_cfg_name:Nn #1#2
-    {
-      \str_set:Nx \l__zhnum_encoding_str {#2}
-      \str_set_eq:NN #1 \l__zhnum_encoding_str
-    }
-  \cs_new_eq:NN \zhnum_reset_config: \zhnum_parse_config:
-\else:
-  \cs_new_protected:Npn \zhnum_set_catcode:
-    { \bool_if:NT \l__zhnum_active_char_bool { \zhnum_set_active: } }
-  \cs_new_protected:Npn \zhnum_set_active:
-    {
-      \str_case:onTF { \l__zhnum_encoding_str }
-        {
-          { gbk }  { \int_set:Nn \l__zhnum_byte_min_int { "81 } }
-          { big5 } { \int_set:Nn \l__zhnum_byte_min_int { "A1 } }
-        }
-        { \int_set:Nn \l__zhnum_byte_max_int { "FE } }
-        {
-          \int_set:Nn \l__zhnum_byte_min_int { "E0 }
-          \int_set:Nn \l__zhnum_byte_max_int { "EF }
-        }
-      \int_step_function:nnN
-        { \l__zhnum_byte_min_int }
-        { \l__zhnum_byte_max_int } \char_set_catcode_active:n
-    }
-  \int_new:N \l__zhnum_byte_min_int
-  \int_new:N \l__zhnum_byte_max_int
-  \cs_new_protected:Npn \zhnum_set_cfg_name:Nn #1#2
-    {
-      \str_set:Nx \l__zhnum_encoding_str {#2}
-      \str_set:Nx #1
-        {
-          \l__zhnum_encoding_str
-          \bool_if:NT \l__zhnum_active_char_bool { _active }
-        }
-    }
-  \cs_new_protected:Npn \zhnum_reset_config:
-    { \zhnum_load_cfg:o { \l__zhnum_encoding_str } }
-  \bool_new:N \l__zhnum_active_char_bool
-  \bool_set_true:N \l__zhnum_active_char_bool
-\fi:
+\cs_new_protected:Npn \zhnum_set_encoding:n #1
+  {
+    \str_set:Nx \l__zhnum_encoding_str
+      { \str_lowercase:n {#1} }
+    \zhnum_load_cfg:o { \l__zhnum_encoding_str }
+  }
+\str_new:N \l__zhnum_encoding_str
 \keys_define:nn { zhnum / options }
   {
     encoding         .choices:nn =
       { UTF8 , GBK , Big5 }
-      {
-        \str_set:Nx \l__zhnum_encoding_str
-          { \exp_args:No \str_lowercase:n { \l_keys_choice_tl } }
-        \zhnum_load_cfg:o { \l__zhnum_encoding_str }
-      } ,
+      { \exp_args:No \zhnum_set_encoding:n { \l_keys_choice_tl } } ,
     encoding          .default:n = { GBK } ,
     encoding / Bg5       .meta:n = { encoding = Big5 } ,
     encoding / unknown   .code:n =
@@ -908,12 +1126,14 @@
     style / Simplified   .code:n = { \bool_set_true:N  \l__zhnum_simp_bool } ,
     style / Traditional  .code:n = { \bool_set_false:N \l__zhnum_simp_bool } ,
     style             .default:n = { Normal , Simplified } ,
+    style              .groups:n = { style } ,
     null             .bool_set:N = \l__zhnum_null_bool ,
+    null               .groups:n = { style } ,
     time .choice: ,
     time / Chinese       .code:n = { \bool_set_true:N \l__zhnum_time_bool } ,
     time / Arabic        .code:n = { \bool_set_false:N  \l__zhnum_time_bool } ,
     time              .default:n = { Arabic } ,
-    reset                .code:n = { \zhnum_reset_config: } ,
+    reset            .bool_set:N = \l__zhnum_reset_bool ,
     activechar       .bool_set:N = \l__zhnum_active_char_bool ,
     ganzhi-cyclic .choice: ,
     ganzhi-cyclic / true .code:n =
@@ -923,23 +1143,73 @@
     ganzhi-cyclic     .default:n = { true } ,
     arabicsep          .tl_set:N = \l__zhnum_arabic_sep_tl
   }
-\str_new:N \l__zhnum_encoding_str
+\bool_new:N \l__zhnum_simp_bool
+\bool_new:N \l__zhnum_normal_bool
+\bool_new:N \l__zhnum_ancient_bool
 \msg_new:nnnn { zhnumber } { encoding-invalid }
   { The~encoding~`#1'~is~invalid. }
   { Available~encodings~are~`UTF8',~`GBK'~and~`Big5'. }
 \NewDocumentCommand \zhnumsetup { +m }
   {
-    \keys_set:nn { zhnum / options } {#1}
+    \zhnum_set:n {#1}
     \tex_ignorespaces:D
   }
-\keys_set:nn { zhnum / options } { style , time , arabicsep = { ~ } }
-\ProcessKeysOptions { zhnum / options }
-\str_if_empty:NT \l__zhnum_encoding_str
+\cs_new_protected:Npn \zhnum_set:n #1
   {
-    \zhnum_if_unicode_engine:TF
-      { \keys_set:nn { zhnum / options } { encoding = UTF8 } }
-      { \keys_set:nn { zhnum / options } { encoding = GBK } }
+    \bool_set_false:N \l__zhnum_reset_bool
+    \keys_set_filter:nnnN { zhnum / options }
+      { style , user } {#1} \l__zhnum_kv_tl
+    \tl_if_empty:NF \l__zhnum_kv_tl
+      { \__zhnum_set_style: }
+    \bool_if:NT \l__zhnum_reset_bool
+      { \zhnum_reset_config: }
   }
+\cs_new_protected:Npn \__zhnum_set_style:
+  {
+    \keys_set_filter:nnoN { zhnum / options }
+      { user } { \l__zhnum_kv_tl } \l__zhnum_tmp_tl
+    \tl_if_empty:NTF \l__zhnum_tmp_tl
+      { \zhnum_reset_style: }
+      {
+        \tl_if_eq:NNF \l__zhnum_tmp_tl \l__zhnum_kv_tl
+          { \zhnum_reset_style: }
+        \bool_if:NF \l__zhnum_reset_bool
+          { \__zhnum_set_user: }
+      }
+  }
+\cs_new_protected:Npn \__zhnum_set_user:
+  {
+    \keys_set_filter:nnoN { zhnum / options }
+      { pre , pos } { \l__zhnum_tmp_tl } \l__zhnum_kv_tl
+    \tl_if_eq:NNF \l__zhnum_kv_tl \l__zhnum_tmp_tl
+      { \zhnum_reset_normal: }
+    \tl_if_empty:NF \l__zhnum_kv_tl
+      { \__zhnum_set_pre_pos: }
+  }
+\cs_new_protected:Npn \__zhnum_set_pre_pos:
+  {
+    \keys_set_filter:nnoN { zhnum / options }
+      { pos } { \l__zhnum_kv_tl } \l__zhnum_tmp_tl
+    \tl_if_eq:NNF \l__zhnum_tmp_tl \l__zhnum_kv_tl
+      {
+        \zhnum_reset_week_day:
+        \zhnum_reset_ganzhi:
+      }
+    \tl_if_empty:NF \l__zhnum_kv_tl
+      { \keys_set:no { zhnum / options } { \l__zhnum_kv_tl } }
+  }
+\cs_generate_variant:Nn \keys_set_filter:nnnN { nno }
+\keys_set:nn { zhnum / options }
+  { style , time , arabicsep = { ~ } }
+\cs_if_exist:NTF \ProcessKeyOptions
+  { \ProcessKeyOptions [ zhnum / options ] }
+  {
+    \RequirePackage { l3keys2e }
+    \ProcessKeysOptions { zhnum / options }
+  }
+\str_if_empty:NTF \l__zhnum_encoding_str
+  { \zhnum_set_encoding:n { UTF8 } }
+  { \zhnum_reset_style: }
 %% 
 %%     This package consists of the file  zhnumber.dtx,
 %%                  and the derived files zhnumber.pdf,



More information about the tex-live-commits mailing list.