% \iffalse meta-comment
% !TEX program  = XeLaTeX
%<*internal>
\iffalse
%</internal>
%<*readme>
zhnumber
========

The `zhnumber` package provides commands to typeset Chinese representations of
numbers. The main difference between this package and `CJKnumb` is that commands
provided by this package is expandable in the proper way. So, it seems that
zhnumber is a good alternative to `CJKnumb` package.

Basic Usage
-----------
The package provides the following macros:

    \zhnumber{<number>}

Convert `<number>` to a full Chinese representation.

    \zhnum{<counter>}

Similar to `\arabic{<counter>}`, but representation of `<counter>`
as Chinese numerals.

    \zhdigits{<number>}
    \zhdigits*{<number>}

Handle `<number>` as a string of digits and convert each of them into the
corresponding Chinese digit. The starred version uses the Chinese circle glyph
for digit zero; the unstarred version uses the traditional glyph.

You can read the package manual (in Chinese) for more detailed explanations.

Contributing
------------

This package is a part of the [ctex-kit](https://github.com/CTeX-org/ctex-kit) project.

Issues and pull requests are welcome.

Copyright and Licence
---------------------

    Copyright (C) 2012, 2014-2016 by Qing Lee <sobenlee@gmail.com>
    ----------------------------------------------------------------------

    This work may be distributed and/or modified under the
    conditions of the LaTeX Project Public License, either
    version 1.3c of this license or (at your option) any later
    version. This version of this license is in
       http://www.latex-project.org/lppl/lppl-1-3c.txt
    and the latest version of this license is in
       http://www.latex-project.org/lppl.txt
    and version 1.3 or later is part of all distributions of
    LaTeX version 2005/12/01 or later.

    This work has the LPPL maintenance status `maintained'.

    The Current Maintainer of this work is Qing Lee.

    This package consists of the file  zhnumber.dtx,
                 and the derived files zhnumber.pdf,
                                       zhnumber.sty,
                                       zhnumber-utf8.cfg,
                                       zhnumber-gbk.cfg,
                                       zhnumber-big5.cfg,
                                       zhnumber.ins and
                                       README.md (this file).
%</readme>
%<*internal>
\fi
\begingroup
  \def\temp{LaTeX2e}
\expandafter\endgroup\ifx\temp\fmtname\else
\csname fi\endcsname
%</internal>
%<*install>

\input ctxdocstrip %

\preamble

    Copyright (C) 2012, 2014-2016 by Qing Lee <sobenlee@gmail.com>
--------------------------------------------------------------------------

    This work may be distributed and/or modified under the
    conditions of the LaTeX Project Public License, either
    version 1.3c of this license or (at your option) any later
    version. This version of this license is in
       http://www.latex-project.org/lppl/lppl-1-3c.txt
    and the latest version of this license is in
       http://www.latex-project.org/lppl.txt
    and version 1.3 or later is part of all distributions of
    LaTeX version 2005/12/01 or later.

    This work has the LPPL maintenance status `maintained'.

    The Current Maintainer of this work is Qing Lee.

--------------------------------------------------------------------------

\endpreamble
\postamble

    This package consists of the file  zhnumber.dtx,
                 and the derived files zhnumber.pdf,
                                       zhnumber.sty,
                                       zhnumber-utf8.cfg,
                                       zhnumber-gbk.cfg,
                                       zhnumber-big5.cfg,
                                       zhnumber.ins and
                                       README.md.
\endpostamble

\generate
  {
%</install>
%<*internal>
    \usedir{source/latex/zhnumber}
    \file{zhnumber.ins}       {\from{\jobname.dtx}{install}}
%</internal>
%<*install>
    \usedir{tex/latex/zhnumber}
    \file{zhnumber.sty}       {\from{\jobname.dtx}{package}}
    \usedir{tex/latex/zhnumber/config}
    \file{zhnumber-utf8.cfg}  {\from{\jobname.dtx}{config,utf8}}
    \file{zhnumber-big5.cfg}  {\from{\jobname.dtx}{config,big5}}
    \file{zhnumber-gbk.cfg}   {\from{\jobname.dtx}{config,gbk}}
    \nopreamble\nopostamble
    \usedir{doc/latex/zhnumber}
    \file{README.md}          {\from{\jobname.dtx}{readme}}
  }

\endbatchfile
%</install>
%<*internal>
\fi
%</internal>
%<package>\NeedsTeXFormat{LaTeX2e}
%<package>\RequirePackage{expl3}
%<+package|config>\GetIdInfo$Id$
%<package>  {Typesetting numbers with Chinese glyphs}
%<config&utf8>  {Chinese numerals with UTF8 encoding}
%<config&big5>  {Chinese numerals with Big5 encoding}
%<config&gbk>  {Chinese numerals with GBK encoding}
%<package>\ProvidesExplPackage{\ExplFileName}
%<config&utf8>\ProvidesExplFile{\ExplFileName-utf8.cfg}
%<config&big5>\ProvidesExplFile{\ExplFileName-big5.cfg}
%<config&gbk>\ProvidesExplFile{\ExplFileName-gbk.cfg}
%<package|config>  {\ExplFileDate}{2.4}{\ExplFileDescription}
%<*driver>
\documentclass{ctxdoc}
\begin{document}
  \DocInput{\jobname.dtx}
  \IndexLayout
  \PrintIndex
\end{document}
%</driver>
% \fi
%
% \CheckSum{1219}
% \GetFileId{zhnumber.sty}
%
% \title{\bfseries\pkg{zhnumber} 宏包}
% \author{李清\\ \path{sobenlee@gmail.com}}
% \date{\filedate\qquad\fileversion\thanks{\ctexkitrev{\ExplFileVersion}.}}
% \maketitle
%
% \begin{documentation}
%
% \section{简介}
% \pkg{zhnumber} 宏包用于将阿拉伯数字按照中文格式输出。相比于 \pkg{CJKnumb}，它提供
% 的四个格式转换命令 \tn{zhnumber}，\tn{zhdigits}、\tn{zhnum} 和 \tn{zhdig}
% 都是可以适当展开的，可以正常使用于 |PDF| 书签和交叉引用。
%
% \pkg{zhnumber} 支持 |GBK|，|Big5| 和 |UTF8| 编码，依赖 \hologo{LaTeX3} 项目的
% \pkg{expl3}，\pkg{xparse} 和 \pkg{l3keys2e} 宏包。
%
% \section{使用方法}
%
% \begin{function}[updated=2014-09-09]{encoding}
%   \begin{syntax}
%     encoding = <GBK|Big5|UTF8>
%   \end{syntax}
%   用于指定编码的宏包选项，可以在调用宏包的时候设定，也可以用 \tn{zhnumsetup}
%   在导言区内设定。对于 \upLaTeX、\XeLaTeX{} 和 \LuaLaTeX，不用指定编码，宏包将
%   自动使用 |UTF8| 编码。只有 \LaTeX{} 和 \pdfLaTeX{} 需要指定编码，如果没有指定，
%   默认将使用 |GBK|。
% \end{function}
%
% \begin{function}[rEXP, updated=2014-09-12]{\zhnumber}
%   \begin{syntax}
%     \tn{zhnumber} \Arg{number}
%   \end{syntax}
%   以中文格式输出数字。这里的数字可以是整数、小数和分数。例如
%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.6\linewidth,gobble=5]
%     \zhnumber{2012020120}\\
%     \zhnumber{2 012 020 120}\\
%     \zhnumber{2,012,020,120}\\
%     \zhnumber{2012.020120}\\
%     \zhnumber{2012.}\\
%     \zhnumber{.2012}\\
%     \zhnumber{20120/20120}\\
%     \zhnumber{/2012}\\
%     \zhnumber{2012/}\\
%     \zhnumber{201;2020/120}
%   \end{SideBySideExample}
% \end{function}
%
% \begin{function}[rEXP, updated=2014-09-09]{\zhdigits}
%   \begin{syntax}
%     \tn{zhdigits}   \Arg{number}
%     \tn{zhdigits} * \Arg{number}
%   \end{syntax}
%   将阿拉伯数字转换为中文数字串。缺省状态下，\tn{zhdigits} 将 0 映射为〇，如果需要
%   将其映射为零，可以使用带星号的形式。例如
%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.6\linewidth,gobble=5]
%     \zhdigits{2012020120}\\
%     \zhdigits*{2012020120}
%   \end{SideBySideExample}
% \end{function}
%
% \begin{function}[rEXP, updated=2016-05-01]{\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]
%     \zhnum{section}
%   \end{SideBySideExample}
% \end{function}
%
% \begin{function}[rEXP, added=2016-05-01]{\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]
%     \zhdig{section}
%   \end{SideBySideExample}
% \end{function}
%
% \begin{function}[rEXP, added=2012-05-25]{\zhweekday}
%   \begin{syntax}
%     \tn{zhweekday} \Arg{yyyy/mm/dd}
%   \end{syntax}
%   输出日期当天的星期。例如
%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.6\linewidth,gobble=5]
%     \zhweekday{2012/5/20}
%   \end{SideBySideExample}
% \end{function}
%
% \begin{function}[rEXP, added=2012-05-25]{\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]
%     \zhdate{2012/5/21}\\
%     \zhdate*{2012/5/21}
%   \end{SideBySideExample}
% \end{function}
%
% \begin{function}[rEXP, added=2012-05-25]{\zhtoday}
%   与 |\today| 类似，以中文输出当天的日期。例如
%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.6\linewidth,gobble=5]
%     \zhtoday
%   \end{SideBySideExample}
% \end{function}
%
% \begin{function}[rEXP, added=2012-05-25]{\zhtime}
%   \begin{syntax}
%     \tn{zhtime} \Arg{hh:mm}
%   \end{syntax}
%   以中文格式输出时间。例如
%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.6\linewidth,gobble=5]
%     \zhtime{23:56}
%   \end{SideBySideExample}
% \end{function}
%
% \begin{function}[rEXP, added=2012-05-25]{\zhcurrtime}
%   输出当前的时间。例如
%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.6\linewidth,gobble=5]
%     \zhcurrtime
%   \end{SideBySideExample}
% \end{function}
%
% \begin{function}[rEXP, added=2015-05-20]{\zhtiangan}
%   \begin{syntax}
%     \tn{zhtiangan} \Arg{number}
%   \end{syntax}
%   输出对应的天干计数。\meta{number} 的正常范围是 1--10，超出范围的数字将输出空值。例如
%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.4\linewidth,gobble=5]
%     \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{syntax}
%     \tn{zhdizhi} \Arg{number}
%   \end{syntax}
%   输出对应的地支计数。\meta{number} 的正常范围是 1--12，超出范围的数字将输出空值。例如
%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.4\linewidth,gobble=5]
%     \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{syntax}
%     \tn{zhganzhi} \Arg{number}
%   \end{syntax}
%   输出对应的干支计数。\meta{number} 的正常范围是 1--60，超出范围的数字将输出空值。例如
%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.4\linewidth,gobble=5]
%     \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{syntax}
%     \tn{zhganzhinian} \Arg{year}
%   \end{syntax}
%   输出公元纪年 \meta{year} 对应的干支纪年。公元前的年份用负数表示。例如
%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.4\linewidth,gobble=5]
%     \zhganzhinian{1898}  \zhganzhinian{-246} \\
%     \zhganzhinian{-2697} \zhganzhinian{\year}
%   \end{SideBySideExample}
% \end{function}
%
% \begin{function}[added=2012-05-25]{\zhnumExtendScaleMap}
%   \begin{syntax}
%     \tn{zhnumExtendScaleMap} \oarg{character} \{<character_1>, <character_2>, ..., <character_n>\}
%   \end{syntax}
%   缺省状态下 \tn{zhnumber} 能正确中文格式化的最大整数是 $10^{48}-1$，\tn{zhdigits} 不受
%   这个大小的限制。可以通过 \tn{zhnumExtendScaleMap} 来扩展 \tn{zhnumber}。
%   \meta{character_i} 设置 $10^{4(i+11)}$。若给出可选项 \meta{character}，则当
%   数字大于 $10^{4(n+12)}-1$ 时，统一用 \meta{character} 设置输出数字的进位。
% \end{function}
%
% \begin{function}{\zhnumsetup}
%   \begin{syntax}
%     \tn{zhnumsetup} \{<key_1>=<val_1>, <key_2>=<val_2>, ...\}
%   \end{syntax}
%   用于在导言区或文档中，设置中文数字的输出格式。目前可以设置的 \meta{key} 如下介绍。
%   以\textbf{粗体}表示选项的默认值。
% \end{function}
%
% \begin{function}[added=2012-05-25]{time}
%   \begin{syntax}
%     time = <(Arabic)|Chinese>
%   \end{syntax}
%   设置日期和时间的数字格式，\meta{Arabic} 为阿拉伯数字，而 \meta{Chinese} 为中文数字。
%   例如
%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.6\linewidth,gobble=5]
%     \zhnumsetup{time=Chinese}
%     \zhtoday\zhcurrtime
%   \end{SideBySideExample}
% \end{function}
%
% \begin{function}[added=2016-05-01]{arabicsep}
%   \begin{syntax}
%     arabicsep = \Arg{sep}
%   \end{syntax}
%   设置日期和时间的数字格式为阿拉伯数字时，阿拉伯数字与汉字的间隔内容。默认为一个空格。
% \end{function}
%
% \begin{function}[updated=2012-05-25]{style}
%   \begin{syntax}
%     style = <(Simplified)|Traditional|(Normal)|Financial|Ancient>
%   \end{syntax}
%   意义分别为
%
%   \begin{description}[font=\mdseries\ttfamily\small,align=right,leftmargin=*,
%                       labelsep=\marginparsep,labelindent=-\marginparsep]
%     \item[Simplified]  以简体中文输出数字（对 |Big5| 编码无效）；
%     \item[Traditional] 以繁体中文输出数字（对 |Big5| 编码无效）；
%     \item[Normal] 以小写形式输出中文数字；
%     \item[Financial]  以大写形式输出中文数字；
%     \item[Ancient] 以廿输出 20，以卅输出 30，以卌输出 40，以皕输出 200。
%   \end{description}
%
%   可以设置 |style| 为其中一个，也可以是前三个与后两个的适当组合，默认是简体小写。例如
%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.4\linewidth,gobble=5]
%     \zhnumsetup{style={Traditional,Financial}}
%     \zhnumber{62012.3}\\
%     \zhnumsetup{style=Ancient}
%     \zhnumber{21}
%   \end{SideBySideExample}
% \end{function}
%
% \begin{function}{null}
%   \begin{syntax}
%     null = <\TFF>
%   \end{syntax}
%   缺省状态下，除了 \tn{zhdigits} 外，其它的格式转换命令，将 0 映射成零，如果需要将 0 映射
%   成〇，可以使用这个选项。
% \end{function}
%
% \begin{function}[added=2015-05-20]{ganzhi-cyclic}
%   \begin{syntax}
%     ganzhi-cyclic = <\TFF>
%   \end{syntax}
%   天干、地支和干支的数字都有一定范围。若参数大于这个范围，\tn{tiangan} 等将输出空值。
%   可以将本选项设置为 |true|，对超出范围的数字取相应的模。
%   请注意，数字 |0| 的结果总是为空值。例如
%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.3\linewidth,gobble=5]
%     \zhnumsetup{ganzhi-cyclic}
%     \zhtiangan{11} \zhtiangan{12} \zhtiangan{209}
%     \zhtiangan{-1} \zhtiangan{-2} \zhtiangan{-683} \\
%     \zhdizhi{13}   \zhdizhi{24}   \zhdizhi{1211}
%     \zhdizhi{-1}   \zhdizhi{-2}   \zhdizhi{-8199}  \\
%     \zhganzhi{61}  \zhganzhi{72}  \zhganzhi{2158}  \\
%     \zhganzhi{-1}  \zhganzhi{-2}  \zhganzhi{-789}
%   \end{SideBySideExample}
% \end{function}
%
%\bigskip
% \pkg{zhnumber} 提供下列选项来控制阿拉伯数字的中文映射。
% \begin{verbatim}[frame=single]
%   - -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
%   T1 T2 T3 T4 T5 T6 T7 T8 T9 T10
%   D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D12
%   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}
% 其中 |-| 设置负，|-0| 设置〇，|dot| 设置小数的点，|and| 和 |parts| 分别设置分数
% 的“又”和“分之”，|E|$n$ 设置 $10^n$，|F|$n$ 设置数字 $n$ 的大写，|T|$n$ 设置
% 数字 $n$ 的天干，|D|$n$ 设置数字 $n$ 的地支，而 |GZ|$n$ 设置数字 $n$ 的干支。
% 其它的选项同字面意思，不再赘述。例如
% \begin{verbatim}[frame=single]
%   \zhnumsetup{2={两}}
% \end{verbatim}
% 可以将 2 映射成两。需要说明的是，\pkg{zhnumber} 将优先使用这里的设置，所以可能会影响
% 到 |style| 选项。如果要恢复 |style| 的功能，可以使用 |reset| 选项。
%
% \begin{function}[updated=2014-09-12]{reset}
%   \begin{syntax}
%     reset
%   \end{syntax}
%   用于恢复 \pkg{zhnumber} 对阿拉伯数字的初始化映射。\pkg{zhnumber} 的中文数字初始化
%   设置见源代码（第 \ref{sec:zhnum-map} 节）。
% \end{function}
%
% \begin{function}[added=2014-09-09]{activechar}
%   \begin{syntax}
%     activechar = <\TTF>
%   \end{syntax}
%   在 \LaTeX{} 或者 \pdfLaTeX{} 下面输出汉字，传统的办法需要将汉字的首字节设置为
%   活动字符，然后再通过特殊的宏技巧来实现。因此，\pkg{zhnumber} 在载入配置文件的
%   时候，默认会将汉字的首字节设置为活动字符。禁用本选项将不会改变汉字首字节的
%   类代码。需要在本选项之后，使用 \texttt{encoding} 或者 \texttt{reset} 选项
%   才会有效果。
% \end{function}
%
% \begin{function}[updated=2016-05-01]{\zhnumber,\zhdigits,\zhnum,\zhdig}
%   \begin{syntax}
%     \tn{zhnumber}   \oarg{options} \Arg{number}
%     \tn{zhdigits} * \oarg{options} \Arg{number}
%     \tn{zhnum}      \oarg{options} \Arg{counter}
%     \tn{zhdig}      \oarg{options} \Arg{counter}
%   \end{syntax}
%   如果只改变当前数字的中文输出格式，可以使用带选项的格式转换命令，其中 \meta{options}
%   与 \tn{zhnumsetup} 的参数相同，如上所介绍。这些带了选项的命令是不可展开的，在某些场合使
%   用时要小心。
% \end{function}
%
% \end{documentation}
%
% \StopEventually{}
%
% \begin{implementation}
%
% \section{\pkg{zhnumber} 宏包代码实现}
%
%    \begin{macrocode}
%<*package>
%    \end{macrocode}
%
%    \begin{macrocode}
%<@@=zhnum>
%    \end{macrocode}
%
%    \begin{macrocode}
\msg_new:nnn { zhnumber } { l3-too-old }
  {
    Support~package~'expl3'~too~old. \\\\
    Please~update~an~up~to~date~version~of~the~bundles\\\\
    'l3kernel'~and~'l3packages'\\\\
    using~your~TeX~package~manager~or~from~CTAN.
  }
\@ifpackagelater { expl3 } { 2015/09/24 } { }
  { \msg_error:nn  { zhnumber }  { l3-too-old } }
%    \end{macrocode}
%
%    \begin{macrocode}
\RequirePackage { xparse , l3keys2e }
%    \end{macrocode}
%
% \begin{macro}{\zhnumber}
% 用于将输入的数字按照中文格式输出。
%    \begin{macrocode}
\DeclareExpandableDocumentCommand \zhnumber { +o +m }
  {
    \IfNoValueTF {#1}
      { \zhnum_number:f }
      { \zhnumberwithoptions {#1} }
    {#2}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\zhnumberwithoptions}
% 带选项的用户函数。
%    \begin{macrocode}
 \NewDocumentCommand \zhnumberwithoptions { +m +m }
  {
    \group_begin:
      \keys_set:nn { zhnum / options } {#1}
      \zhnum_number:f {#2}
    \group_end:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\zhnum_number:n}
% \begin{macro}[aux]{\@@_number:www}
% 先判断输入的是小数还是分数。
%    \begin{macrocode}
\cs_new:Npn \zhnum_number:n #1
  { \@@_number:www #1 . \q_nil . \q_stop }
\cs_new:Npn \@@_number:www #1 . #2 . #3 \q_stop
  {
    \quark_if_nil:nTF {#2}
      { \@@_integer_or_fraction:www #1 / \q_nil / \q_stop }
      { \zhnum_decimal:nn {#1} {#2} }
  }
\cs_generate_variant:Nn \zhnum_number:n { f }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[aux]{\@@_integer_or_fraction:www}
% 判断是否输入的是分数。
%    \begin{macrocode}
\cs_new:Npn \@@_integer_or_fraction:www #1 / #2 / #3 \q_stop
  {
    \quark_if_nil:nTF {#2}
      { \zhnum_integer:n {#1} }
      { \@@_fraction:wwww #2 \q_mark #1 ; \q_nil ; \q_stop }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[aux]{\@@_fraction:wwww}
% 对分数进行预处理。
%    \begin{macrocode}
\cs_new:Npn \@@_fraction:wwww #1 \q_mark #2 ; #3 ; #4 \q_stop
  {
    \quark_if_nil:nTF {#3}
      {
        \zhnum_blank_to_zero:n {#1}
        \c_@@_parts_tl
        \zhnum_blank_to_zero:n {#2}
      }
      {
        \tl_if_blank:nF {#2}
          {
            \zhnum_number:n {#2}
            \c_@@_and_tl
          }
        \zhnum_blank_to_zero:n {#1}
        \c_@@_parts_tl
        \zhnum_blank_to_zero:n {#3}
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\zhnum_decimal:nn}
% 对小数进行预处理。
%    \begin{macrocode}
\cs_new:Npn \zhnum_decimal:nn #1#2
  {
    \zhnum_blank_to_zero:n {#1} \c_@@_dot_tl
    \tl_if_blank:nTF {#2}
      { \c_@@_zero_tl }
      { \zhnum_digits_zero:n {#2} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\zhnum_blank_to_zero:n}
% 输出小数的整数位。
%    \begin{macrocode}
\cs_new:Npn \zhnum_blank_to_zero:n #1
  {
    \tl_if_blank:nTF {#1}
      { \c_@@_zero_tl }
      { \zhnum_number:n {#1} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\zhnum,\zhnumberwithoptions}
% 用于将 \LaTeX{} 计数器按中文格式输出。
%    \begin{macrocode}
\DeclareExpandableDocumentCommand \zhnum { +o +m }
  {
    \IfNoValueTF {#1}
      { \zhnum_counter:n }
      { \zhnumwithoptions {#1} }
    {#2}
  }
\NewDocumentCommand \zhnumwithoptions { +m +m }
  {
    \group_begin:
      \keys_set:nn { zhnum / options } {#1}
      \zhnum_counter:n {#2}
    \group_end:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\zhnum_counter:n, \zhnum_int:n}
% 可以直接通过比较 \LaTeX{} 计数器的值来得到符号和绝对值。
%    \begin{macrocode}
\cs_new:Npn \zhnum_counter:n #1
  {
    \int_if_exist:cTF { c@#1 }
      { \zhnum_int:c { c@#1 } }
      { \@@_counter_error:n {#1} }
  }
\cs_new:Npn \@@_counter_error:n #1
  { \msg_expandable_error:nnn { zhnumber } { not-counter } {#1} }
\msg_new:nnn  { zhnumber } { not-counter }
  { `#1'~is~not~a~LaTeX~counter. }
\cs_new:Npn \zhnum_int:n #1
  {
    \int_compare:nNnTF {#1} > \c_zero
      { \zhnum_parse_number:f { \int_eval:n {#1} } }
      {
        \int_compare:nNnTF {#1} < \c_zero
          {
            \c_@@_minus_tl
            \zhnum_parse_number:f { \int_eval:n { - #1 } }
          }
          { \c_@@_zero_tl }
      }
  }
\cs_generate_variant:Nn \zhnum_int:n { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@zhnum}
% 用于支持 |\pagenumbering{zhnum}|。
%    \begin{macrocode}
\cs_new_nopar:Npn \@zhnum { \zhnum_int:n }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\zhnum_integer:n}
% 对整数的处理。这个函数基本抄录自 \pkg{l3bigint} 的 \cs{__bingint_read_do:nn}。它可以
% 正确取得符号，去掉多余的零，还可以循环展开数字。但它在遇到非数字的时候就停止了
% 循环，我们可能需要非数字（例如逗号）来作为分隔符号。因此对它略作修改，跳过非数字。
%    \begin{macrocode}
\cs_new:Npn \zhnum_integer:n #1
  {
    \exp_after:wN \@@_read_integer:www
    \tex_number:D
      \exp_after:wN \@@_read_sign_loop:N
      \exp:w \exp_end_continue_f:w \use:n
      #1 \exp_stop_f: \q_recursion_tail \q_recursion_stop
         \@@_result:nn { \c_zero } { } ;
  }
\cs_new:Npn \@@_read_sign_loop:N #1
  {
    \if:w + \if:w - \exp_not:N #1 + \fi: \exp_not:N #1
      \exp_after:wN \@@_read_sign_loop:N
      \exp:w \exp_end_continue_f:w \exp_after:wN \use:n
    \else:
      1 \exp_after:wN ;
      \exp:w \exp_end_continue_f:w
        \exp_after:wN \@@_read_zeros_loop:N
        \exp_after:wN #1
    \fi:
  }
\cs_new:Npn \@@_read_zeros_loop:N #1
  {
    \if:w 0 \exp_not:N #1
      \exp_after:wN \@@_read_zeros_loop:N
      \exp:w \exp_end_continue_f:w \exp_after:wN \use:n
    \else:
      \exp_after:wN \@@_read_abs_loop:Nw
      \exp_after:wN #1
    \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[aux]{\@@_read_abs_loop:Nw}
% 当数字很大时，\pkg{l3bigint} 的实现会造成 \TeX{} 内存溢出：
% \begin{verbatim}
%   ! TeX capacity exceeded, sorry [expansion depth=10000].
% \end{verbatim}
% 我们在这里参考 \cs{__tl_act:NNNnn} 的实现对它进行了改进。
%    \begin{macrocode}
\cs_new:Npn \@@_read_abs_loop:Nw #1#2 \q_recursion_stop
  {
    \zhnum_if_digit:NTF #1
      { \@@_output:nnwnn { + \c_one } #1 }
      { \quark_if_recursion_tail_stop_do:Nn #1 { \@@_loop_end:wnn } }
    \exp_after:wN \@@_read_abs_loop:Nw
      \exp:w \exp_end_continue_f:w \use:n #2 \q_recursion_stop
  }
\cs_new:Npn \@@_output:nnwnn #1#2#3 \@@_result:nn #4#5
  { #3 \@@_result:nn { #4#1 } { #5#2 } }
\cs_new:Npn \@@_loop_end:wnn #1 \@@_result:nn #2#3
  { \int_eval:n {#2} ; #3 }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[aux]{\@@_read_integer:www}
% |#1| 符号，|#3| 是绝对值，|#2| 是绝对值的长度。
%    \begin{macrocode}
\cs_new:Npn \@@_read_integer:www #1 ; #2 ; #3 ;
  {
    \int_compare:nNnTF {#2} = \c_zero
      { \c_@@_zero_tl }
      {
        \int_compare:nNnF {#1} = \c_one
          { \c_@@_minus_tl }
        \zhnum_parse_number:nn {#2} {#3}
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\zhnum_if_digit:NTF}
% 判断 |#1| 是否为数字位。
%    \begin{macrocode}
\cs_new:Npn \zhnum_if_digit:NTF #1
  {
    \if_int_compare:w \c_nine < 1 \exp_not:N #1 \exp_stop_f:
      \exp_after:wN \use_i:nn
    \else:
      \exp_after:wN \use_ii:nn
    \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
%   {
%     \zhnum_parse_number:n,
%     \zhnum_parse_number:nn
%   }
%    \begin{macrocode}
\cs_new:Npn \zhnum_parse_number:n #1
  { \exp_args:Nf \zhnum_parse_number:nn { \tl_count:n {#1} } {#1} }
\cs_new:Npn \zhnum_parse_number:nn #1
  { \exp_args:Nf \@@_parse_number:nnn { \int_mod:nn {#1} \c_four } {#1} }
\cs_new:Npn \@@_parse_number:nnn #1#2
  {
    \int_compare:nNnTF {#2} < \c_two
      { \zhnum_digit_map:n }
      {
        \int_compare:nNnTF {#1} = \c_zero
          { \zhnum_split_number:fn { \int_eval:n { #2 / \c_four - \c_one } } }
          { \@@_split_number_aux:nnn {#1} {#2} }
      }
  }
\cs_generate_variant:Nn \zhnum_parse_number:n { f }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[aux]{\@@_split_number_aux:nnn}
% 为了处理的方便，在整数前面补上适当的 $0$，使其位数可以被 $4$ 整除。
%    \begin{macrocode}
\cs_new:Npn \@@_split_number_aux:nnn #1#2
  {
    \exp_after:wN \@@_split_number_aux:wwn
      \tex_number:D \int_div_truncate:nn {#2} \c_four
        \if_case:w #1 \exp_stop_f:
          \or: \exp_after:wN \use:n
          \or: \exp_after:wN \use_i_ii:nnn
          \or: \exp_after:wN \use_i:nnn
        \fi:
        { \exp_stop_f: ; 0 } 0 0 ;
  }
\cs_new:Npn \@@_split_number_aux:wwn #1 ; #2 ; #3
  { \zhnum_split_number:nn {#1} { #2#3 } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\zhnum_split_number:nn}
% 最后加入的 \cs{q_recursion_tail} 是停止递归的标志，而 \cs{q_nil} 用于占位。
%    \begin{macrocode}
\cs_new:Npn \zhnum_split_number:nn #1#2
  {
    \zhnum_split_number:NNnNNNNw \c_true_bool \c_true_bool {#1}
      #2 \q_recursion_tail \q_nil \q_nil \q_nil \q_recursion_stop
  }
\cs_generate_variant:Nn \zhnum_split_number:nn { f }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\zhnum_split_number:NNnNNNNw}
% 将输入的整数由高位到低位，以四位为一段进行处理。
%    \begin{macrocode}
\cs_new:Npn \zhnum_split_number:NNnNNNNw #1#2#3#4#5#6#7
  {
    \quark_if_recursion_tail_stop:N #4
    \int_compare:nNnTF { #4#5#6#7 } = \c_zero
      { \use_i:nn }
      {
        \bool_if:NF #1 { \c_@@_zero_tl }
        \zhnum_process_number:NNNNNN #4#5#6#7#1#2
        \zhnum_scale_map:n {#3}
        \int_compare:nNnTF {#7} = \c_zero
      }
      { \zhnum_split_number:NNfNNNNw \c_false_bool \c_true_bool }
      { \zhnum_split_number:NNfNNNNw \c_true_bool  \c_false_bool }
    { \int_eval:n { #3 - \c_one } }
  }
\cs_generate_variant:Nn \zhnum_split_number:NNnNNNNw { NNf }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\zhnum_process_number:NNNNNN}
% 对四位数字按情况进行处理。
%    \begin{macrocode}
\cs_new:Npn \zhnum_process_number:NNNNNN #1#2#3#4#5#6
  {
    \int_compare:nNnTF {#1} = \c_zero
      { \bool_if:NF #6 { \c_@@_zero_tl } }
      { \zhnum_digit_map:n {#1} \c_@@_thousand_tl }
    \int_compare:nNnTF {#2} = \c_zero
      { \int_compare:nNnF { #1 * (#3#4) } = \c_zero { \c_@@_zero_tl } }
      {
        \bool_if:nTF
          { \l_@@_ancient_bool && \int_compare_p:nNn {#2} = \c_two }
          { \zhnum_digit_map:n { #2 00 } }
          { \zhnum_digit_map:n {#2} \c_@@_hundred_tl }
      }
    \int_compare:nNnTF {#3} = \c_zero
      { \int_compare:nNnF { #2 * #4 } = \c_zero { \c_@@_zero_tl } }
      {
        \bool_if:nF
          {
            \int_compare_p:nNn {#3}   = \c_one  &&
            \int_compare_p:nNn {#1#2} = \c_zero && #6 && #5
          }
          {
            \bool_if:nTF
              {
                \l_@@_ancient_bool                   &&
                ( \int_compare_p:nNn {#3} = \c_two   ||
                  \int_compare_p:nNn {#3} = \c_three ||
                  \int_compare_p:nNn {#3} = \c_four )
              }
              { \zhnum_digit_map:n { #3 0 } \use_none:n }
              { \zhnum_digit_map:n {#3} }
          }
        \c_@@_ten_tl
      }
    \int_compare:nNnF {#4} = \c_zero { \zhnum_digit_map:n {#4} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\zhdig}
% 用于将 \LaTeX{} 计数器按中文数字串输出。
%    \begin{macrocode}
\DeclareExpandableDocumentCommand \zhdig { +o +m }
  {
    \IfNoValueTF {#1}
      { \zhnum_digits_counter:n }
      { \zhdigwithoptions {#1} }
    {#2}
  }
\NewDocumentCommand \zhdigwithoptions { +m +m }
  {
    \group_begin:
      \keys_set:nn { zhnum / options } {#1}
      \zhnum_digits_counter:n #1 {#2}
    \group_end:
  }
\cs_new:Npn \zhnum_digits_counter:n #1
  {
    \int_if_exist:cTF { c@#1 }
      { \zhnum_digits_null:v { c@#1 } }
      { \@@_counter_error:n {#1} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@zhdig}
% 用于支持 |\pagenumbering{zhdig}|。
%    \begin{macrocode}
\cs_new_nopar:Npn \@zhdig #1 { \zhnum_digits_null:f { \int_eval:n {#1} } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\zhdigits,\zhdigitswithoptions}
% 将输入的数字输出为中文数字串输出。
%    \begin{macrocode}
\DeclareExpandableDocumentCommand \zhdigits { +s +o +m }
  {
    \IfNoValueTF {#2}
      { \zhnum_digits:Nn #1 }
      { \zhdigitswithoptions {#1} {#2} }
    {#3}
  }
\NewDocumentCommand \zhdigitswithoptions { +m +m +m }
  {
    \group_begin:
      \keys_set:nn { zhnum / options } {#2}
      \zhnum_digits:Nn #1 {#3}
    \group_end:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\zhnum_digits_zero:n,\zhnum_digits_null:n}
% 快捷方式。
%    \begin{macrocode}
\cs_new_nopar:Npn \zhnum_digits_zero:n
  { \zhnum_digits:Nn \BooleanTrue }
\cs_new_nopar:Npn \zhnum_digits_null:n
  { \zhnum_digits:Nn \BooleanFalse }
\cs_generate_variant:Nn \zhnum_digits_null:n { V , v , f }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\zhnum_digits:Nn}
% 与 \cs{zhnum_integer:n} 类似，但不用去掉多余的零。
%    \begin{macrocode}
\cs_new:Npn \zhnum_digits:Nn #1#2
  {
    \exp_after:wN \@@_read_digits:w
    \tex_number:D
      \exp_after:wN \@@_read_sign_loop:NN \exp_after:wN #1
      \exp:w \exp_end_continue_f:w \use:n
      #2 \exp_stop_f: \q_recursion_tail \q_recursion_stop
  }
\cs_new:Npn \@@_read_sign_loop:NN #1#2
  {
    \if:w + \if:w - \exp_not:N #2 + \fi: \exp_not:N #2
      \exp_after:wN \@@_read_sign_loop:NN \exp_after:wN #1
      \exp:w \exp_end_continue_f:w \exp_after:wN \use:n
    \else:
      1 \exp_after:wN ;
        \exp_after:wN \@@_read_digits_loop:NN
        \exp_after:wN #1
        \exp_after:wN #2
    \fi:
  }
\cs_new:Npn \@@_read_digits_loop:NN #1#2
  {
    \zhnum_if_digit:NTF #2
      { \@@_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:
      }
    \exp_after:wN \@@_read_digits_loop:NN \exp_after:wN #1
      \exp:w \exp_end_continue_f:w \use:n
  }
\cs_new:Npn \@@_read_digits:w #1 ;
  {
    \int_compare:nNnF {#1} = \c_one
      { \c_@@_minus_tl }
  }
\cs_new:Npn \@@_output_digits:NN #1#2
  {
    \cs:w
      c_@@_
        \if_int_compare:w #2 = \c_zero
          \IfBooleanTF #1 { zero } { null }
        \else:
          #2
        \fi:
      _tl
    \cs_end:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\zhdate}
% 输出中文日期。
%    \begin{macrocode}
\DeclareExpandableDocumentCommand \zhdate { +s +m }
  {
    \@@_date:www #2 \q_stop
    \IfBooleanT #1
      { \@@_week_day:www #2 \q_stop }
  }
\cs_new:Npn \@@_date:www #1/#2/#3 \q_stop
  { \@@_date_aux:nnn {#1} {#2} {#3} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\zhtoday}
% 输出当天日期。
%    \begin{macrocode}
\cs_new_nopar:Npn \zhtoday
  { \@@_date_aux:Vnn \tex_year:D \tex_month:D \tex_day:D }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_date_aux:nnn}
%    \begin{macrocode}
\cs_new_nopar:Npn \@@_date_aux:nnn
  {
    \bool_if:NTF \l_@@_time_bool
      { \@@_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: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
  }
\cs_generate_variant:Nn \@@_date_aux:nnn { V }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\zhweekday}
% 输出星期
%    \begin{macrocode}
\cs_new:Npn \zhweekday #1
  { \@@_week_day:www #1 \q_stop }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_week_day:www}
% 用 Zeller 公式计算的结果 $h$ 与实际星期的关系是 $d=h+5\pmod7+1$。
%    \begin{macrocode}
\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
    \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\zhnum_Zeller:nnn,\zhnum_Zeller_aux:Nnnn,\zhnum_two_digits:n}
% 用 Zeller 公式\footnote{\url{http://en.wikipedia.org/wiki/Zeller's_congruence}}
% 计算星期几。
%    \begin{macrocode}
\cs_new:Npn \zhnum_Zeller:nnn #1#2#3
  {
    \int_compare:nNnTF
      { #1 \zhnum_two_digits:n {#2} \zhnum_two_digits:n {#3} } > { 1582 10 04 }
      { \@@_Zeller_aux:Nnnn \zhnum_Zeller_Gregorian:nnn }
      { \@@_Zeller_aux:Nnnn \zhnum_Zeller_Julian:nnn }
    {#1} {#2} {#3}
  }
\cs_new:Npn \@@_Zeller_aux:Nnnn  #1#2#3#4
  {
    \int_compare:nNnTF {#3} < \c_three
      { #1 { #2 - \c_one } { #3 + \c_twelve } {#4} }
      { #1 {#2} {#3} {#4} }
  }
\cs_new:Npn \zhnum_two_digits:n #1
  {
    \int_compare:nNnT {#1} < \c_ten { 0 }
    \int_eval:n {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\zhnum_Zeller_Gregorian:nnn}
% 格里历（\zhdate{1582/10/15}及以后）的计算公式
% \[
%   h = \biggl(q + \biggl\lfloor\frac{26(m+1)}{10}\biggr\rfloor + Y +
%   \biggl\lfloor\frac Y4\biggr\rfloor + 6\biggl\lfloor\frac Y{100}\biggr\rfloor
%   + \biggl\lfloor\frac Y{400}\biggr\rfloor\biggr) \pmod 7
% \]
% 其中 $Y$ 为年，$m$ 为月，$q$ 为日；若 $m=1,2$，则令 $m\mathbin{{+}{=}}12$，同时 $Y\mathop{--}{}$。
%    \begin{macrocode}
\cs_new:Npn \zhnum_Zeller_Gregorian:nnn #1#2#3
  {
    \int_mod:nn
      {
          (#3)
        + \int_div_truncate:nn { 26 * ( #2 + \c_one ) } \c_ten
        + (#1)
        + \int_div_truncate:nn {#1} \c_four
        + \c_six * \int_div_truncate:nn {#1} \c_one_hundred
        + \int_div_truncate:nn {#1} { 400 }
      }
      { \c_seven }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\zhnum_Zeller_Julian:nnn}
% 儒略历（\zhdate{1582/10/04}及以前）的计算公式
% \[
%   h = \biggl(q + \biggl\lfloor\frac{26(m+1)}{10}\biggr\rfloor + Y +
%   \biggl\lfloor\frac Y4\biggr\rfloor + 5\biggr) \pmod 7
% \]
%    \begin{macrocode}
\cs_new:Npn \zhnum_Zeller_Julian:nnn #1#2#3
  {
    \int_mod:nn
      {
          (#3)
        + \int_div_truncate:nn { 26 * ( #2 + \c_one ) } \c_ten
        + (#1)
        + \int_div_truncate:nn {#1} \c_four
        + \c_five
      }
      { \c_seven }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\zhtime}
% 输出时间。
%    \begin{macrocode}
\cs_new:Npn \zhtime #1
  { \@@_time:ww #1 \q_stop }
\use:x
  {
    \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}
% \end{macro}
%
% \begin{macro}{\zhcurrtime}
% 输出当前时间。
%    \begin{macrocode}
\cs_new_nopar:Npn \zhcurrtime
  {
    \@@_time_aux:nn
      { \int_div_truncate:nn \tex_time:D { 60 } }
      { \int_mod:nn \tex_time:D { 60 } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[aux]{\@@_time_aux:nn,\@@_time_aux:Nnnn}
%    \begin{macrocode}
\cs_new_nopar:Npn \@@_time_aux:nn
  {
    \bool_if:NTF \l_@@_time_bool
      { \@@_time_aux:Nnnn \zhnum_int:n { } }
      { \@@_time_aux:Nnnn \int_to_arabic:n { \l_@@_arabic_sep_tl } }
  }
\cs_new:Npn \@@_time_aux:Nnnn #1#2#3#4
  {
    #1 {#3} #2 \c_@@_hour_tl #2
    #1 {#4} #2 \c_@@_minute_tl
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\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}[internal]{\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 }
      { \zhnum_scale_map_hook:n {#1} }
  }
\cs_new:Npn \zhnum_scale_map_loop:n #1
  { \zhnum_scale_map:n { \int_mod:nn {#1} \l_@@_scale_int } }
\cs_generate_variant:Nn \zhnum_scale_map:n { f }
\int_new:N \l_@@_scale_int
\int_set_eq:NN \l_@@_scale_int \c_eleven
\cs_new_eq:NN \zhnum_scale_map_hook:n \zhnum_scale_map_loop:n
\tl_const:cn { c_@@_s0_tl } { }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\zhnumExtendScaleMap}
% 扩展进位系统。
%    \begin{macrocode}
\NewDocumentCommand \zhnumExtendScaleMap { > { \TrimSpaces } +o +m }
  {
    \int_zero:N \l_tmpa_int
    \clist_map_function:nN {#2} \zhnum_set_scale:n
    \IfNoValueF {#1}
      { \cs_set:Npn \zhnum_scale_map_hook:n ##1 {#1} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\zhnum_set_scale:n}
%    \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 + \c_eleven } _tl }
    \tl_if_exist:cF { \l_tmpa_tl }
      { \int_incr:N \l_@@_scale_int }
    \tl_set:cn { \l_tmpa_tl } {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\zhnum_ganzhi_normal:nnn}
% 保证干支的参数为正数。
%    \begin{macrocode}
\cs_new:Npn \zhnum_ganzhi_normal:nnn #1#2#3
  {
    \int_compare:nNnF {#1} < \c_one
      { \cs_if_exist_use:c { c_@@_ #2 _ #1 _tl } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\zhnum_ganzhi_cyclic:nnn}
% \begin{macro}[aux]{\@@_ganzhi_cyclic_mod:nnnn}
% 对超出范围的数字取模，参数 |0| 的结果是空值。
%    \begin{macrocode}
\cs_new:Npn \zhnum_ganzhi_cyclic:nnn #1#2#3
  {
    \int_compare:nNnF {#1} = \c_zero
      {
        \cs_if_exist_use:cF { c_@@_ #2 _ #1 _tl }
          {
            \@@_ganzhi_cyclic_mod:fnnn
              { \int_mod:nn {#1} {#3} } {#1} {#2} {#3}
          }
      }
  }
\cs_new:Npn \@@_ganzhi_cyclic_mod:nnnn #1#2#3#4
  {
    \int_compare:nNnTF {#2} > \c_zero
      { \use:c { c_@@_ #3 _ #1 _tl } }
      {
        \int_compare:nNnTF {#1} = \c_zero
          { \use:c { c_@@_ #3 _ 1 _tl } }
          { \use:c { c_@@_ #3 _ \int_eval:n {  #1 + #4 + 1 } _tl } }
      }
  }
\cs_generate_variant:Nn \@@_ganzhi_cyclic_mod:nnnn { f }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[internal]{\zhnum_ganzhi:nnn}
% 默认不对超出范围的数字取模。
%    \begin{macrocode}
\cs_new_eq:NN \zhnum_ganzhi:nnn \zhnum_ganzhi_normal:nnn
\cs_generate_variant:Nn \zhnum_ganzhi:nnn { f }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\zhtiangan}
% 天干。
%    \begin{macrocode}
\cs_new:Npn \zhtiangan #1
  { \zhnum_ganzhi:fnn { \int_eval:n {#1} } { tiangan } { 10 } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\zhdizhi}
% 地支。
%    \begin{macrocode}
\cs_new:Npn \zhdizhi #1
  { \zhnum_ganzhi:fnn { \int_eval:n {#1} } { dizhi } { 12 } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\zhganzhi}
% 干支。
%    \begin{macrocode}
\cs_new:Npn \zhganzhi #1
  { \zhnum_ganzhi:fnn { \int_eval:n {#1} } { ganzhi } { 60 } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\zhganzhinian}
% 干支纪年。
%    \begin{macrocode}
\cs_new:Npn \zhganzhinian #1
  { \zhnum_ganzhi_nian:f { \int_eval:n {#1} } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\zhnum_ganzhi_nian:n}
% 干支纪年。公元元年是 |\zhganzhi{58}|。
%    \begin{macrocode}
\cs_new:Npn \zhnum_ganzhi_nian:n #1
  {
    \int_compare:nNnTF {#1} > \c_zero
      { \use:c { c_@@_ganzhi_ \int_mod:nn { #1 + 57 } { 60 } _tl } }
      {
        \int_compare:nNnF {#1} = \c_zero
          {
            \use:c
              {
                c_@@_ganzhi_
                  \int_eval:n { \int_mod:nn { #1 - 2 } { 60 } + 60 }
                _tl
              }
          }
      }
  }
\cs_generate_variant:Nn \zhnum_ganzhi_nian:n { f }
%    \end{macrocode}
% \end{macro}
%
% 根据需要设置中文阿拉伯数字。
%    \begin{macrocode}
\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 } ,
    }
  \int_step_inline:nnnn { 1 } { 1 } { 10 }
    {
      \tl_put_right:Nx \l_tmpa_tl
        {
            #1 .tl_set:N = \exp_not:c { l_@@_ #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:nnnn { 11 } { 1 } { 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
        {
           #1 .tl_set:N = \exp_not:c { l_@@_ #1 _tl } ,
          F#1 .tl_set:N = \exp_not:c { l_@@_financial_ #1 _tl } ,
        }
    }
  \clist_map_inline:nn { 20 , 30 , 40 , 200 }
    {
      \tl_put_right:Nx \l_tmpa_tl
        { #1 .tl_set:N = \exp_not:c { l_@@_ #1 _tl } , }
    }
  \clist_map_inline:nn
    {
      dot , and , parts , year , month , day , weekday , hour , minute
      mon , tue , wed , thu , fri , sat , sun
    }
    {
      \tl_put_right:Nx \l_tmpa_tl
        { #1 .tl_set:N = \exp_not:c { l_@@_ #1 _tl } , }
    }
\use:x
  {
    \group_end:
    \keys_define:nn { zhnum / options } { \exp_not:o \l_tmpa_tl }
  }
%    \end{macrocode}
%
% \begin{macro}[internal]
%   {
%     \zhnum_set_digits_map:nn,
%     \zhnum_set_digits_map:nnn,
%     \zhnum_set_financial_map:nn,
%     \zhnum_set_financial_map:nnn,
%     \zhnum_set_tiangan_map:nn,
%     \zhnum_set_dizhi_map:nn,
%     \l_@@_cfg_map_prop,
%     \l_@@_cfg_map_var_prop,
%     \l_@@_cfg_map_finan_prop,
%     \l_@@_cfg_map_ganzhi_prop
%   }
% 将配置文件中的中文数字保存到 \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: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: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} }
\prop_new:N \l_@@_cfg_map_prop
\prop_new:N \l_@@_cfg_map_var_prop
\prop_new:N \l_@@_cfg_map_finan_prop
\prop_new:N \l_@@_cfg_map_ganzhi_prop
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
%   {
%     \zhnum_parse_config:,
%     \zhnum_check_simp:nn,
%     \zhnum_check_financial:nn,
%     \zhnum_set_zero:,
%     \zhnum_set_week_day:
%   }
% 将 \texttt{prop} 表转化到单独的 \texttt{tl} 变量。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \zhnum_parse_config:
  {
    \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
      }
  }
\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 } }
  }
\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: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 }
          }
      }
      { \tl_set:cn { l_@@_ #2 _tl } {#1} }
  }
\cs_new_protected_nopar:Npn \zhnum_assgin_const:
  {
    \prop_map_function:NN \l_@@_cfg_map_prop \zhnum_check_financial:nn
    \zhnum_set_alias:
  }
\cs_new_protected:Npn \zhnum_check_financial:nn #1#2
  {
    \prop_get:NnNTF \l_@@_cfg_map_finan_prop {#1} \l_tmpa_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 } }
          }
      }
      {
        \zhnum_assgin_const_tl:cx
          { c_@@_ #1 _tl } { \exp_not:c { l_@@_ #1 _tl } }
      }
  }
\cs_new_protected_nopar:Npn \zhnum_set_zero:
  {
    \tl_set:cx { l_@@_0_tl }
      {
        \exp_not:n { \bool_if:NTF \l_@@_null_bool }
          { \exp_not:o \l_@@_null_tl } { \exp_not:v { l_@@_0_tl } }
      }
  }
\cs_new_protected_nopar: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 }
  }
\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
  { \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 {#2} {#1} }
\int_step_inline:nnnn { 1 } { 1 } { 60 }
  {
    \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 }
      }
  }
\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
  {
    \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
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\zhnum_set_alias:}
% 一些易于使用的别名。
%    \begin{macrocode}
\cs_new_eq:NN \zhnum_set_alias:NN \cs_new_eq:NN
\cs_new_protected_nopar:Npx \zhnum_set_alias:
  {
    \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 }
  }
\AtEndOfPackage
  { \cs_set_eq:NN \zhnum_set_alias:NN \tl_set_eq:NN }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\zhnum_load_cfg:n}
% 根据选定编码载入配置文件。
%    \begin{macrocode}
\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:
  }
\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 }
      { \zhnum_input_cfg:n {#1} }
    \@@_update_cfg_prop:N \prop_set_eq:Nc
  }
\cs_new_protected:Npn \zhnum_input_cfg:n #1
  {
    \file_if_exist_input:nTF { zhnumber - #1 .cfg }
      {
        \bool_set_false:N \l_@@_reset_bool
        \@@_update_cfg_prop:N \@@_prop_initial:Nn
        \group_begin:
          \zhnum_set_catcode:
      }
      {
        \msg_error:nnx { zhnumber } { file-not-found } {#1}
        \use_none:nnn
      }
    \@@_update_cfg_prop:N \@@_prop_gset_eq:Nn
    \group_end:
  }
\cs_new_protected:Npn \@@_update_cfg_prop:N #1
  {
    #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 }
  }
\cs_new_protected:Npn \@@_prop_initial:Nn #1#2
  {
    \prop_clear:N #1
    \prop_new:c {#2}
  }
\cs_new_protected:Npn \@@_prop_gset_eq:Nn #1#2
  { \prop_gset_eq:cN {#2} #1 }
\str_new:N \l_@@_cfg_str
\str_new:N \l_@@_last_cfg_str
\bool_new:N \l_@@_reset_bool
\msg_new:nnnn  { zhnumber } { file-not-found }
  { File~`#1'~not~found. }
  {
    The~requested~file~could~not~be~found~in~the~current~directory,~
    in~the~TeX~search~path~or~in~the~LaTeX~search~path.
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal,pTF]{\zhnum_if_unicode_engine:}
% 使用 \upTeX{} 的时候，也不必将汉字的首字符设置为活动字符。判断 |^^^^0021| 是否为
% 单个记号的办法对 \upTeX{} 不适用。
%    \begin{macrocode}
\bool_if:nTF
  {
    \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}
%
% \begin{macro}[internal]
%   {
%     \zhnum_set_catcode:,
%     \zhnum_set_cfg_name:Nn,
%     \zhnum_reset_config:
%   }
% 设置与恢复配置文件前后的 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_nopar:Npn \zhnum_set_catcode:
    { \bool_if:NT \l_@@_active_char_bool { \zhnum_set_active: } }
  \cs_new_protected_nopar: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:nnnN
        { \l_@@_byte_min_int } { \c_one }
        { \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_nopar: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:
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{encoding,style,null,reset}
% 宏包设置选项。
%    \begin{macrocode}
\keys_define:nn { zhnum / options }
  {
    encoding         .choices:nn =
      { UTF8 , GBK , Big5 }
      {
        \str_set:Nx \l_@@_encoding_str
          { \str_fold_case:V \l_keys_choice_tl }
        \zhnum_load_cfg:o { \l_@@_encoding_str }
      } ,
    encoding          .default:n = { GBK } ,
    encoding / Bg5       .meta:n = { encoding = Big5 } ,
    encoding / unknown   .code:n =
      { \msg_error:nnn { zhnumber } { encoding-invalid } {#1} } ,
    style .multichoice: ,
    style / Normal       .code:n =
      {
        \bool_set_false:N \l_@@_ancient_bool
        \bool_set_true:N  \l_@@_normal_bool
      } ,
    style / Financial    .code:n =
      {
        \bool_set_false:N \l_@@_ancient_bool
        \bool_set_false:N \l_@@_normal_bool
      } ,
    style / Ancient      .code:n =
      {
        \bool_set_true:N \l_@@_ancient_bool
        \bool_set_true:N \l_@@_normal_bool
      } ,
    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 } ,
    null             .bool_set:N = \l_@@_null_bool ,
    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: } ,
    activechar       .bool_set:N = \l_@@_active_char_bool ,
    ganzhi-cyclic .choice: ,
    ganzhi-cyclic / true .code:n =
      { \cs_set_eq:NN \zhnum_ganzhi:nnn \zhnum_ganzhi_cyclic:nnn } ,
    ganzhi-cyclic / false.code:n =
      { \cs_set_eq:NN \zhnum_ganzhi:nnn \zhnum_ganzhi_normal:nnn } ,
    ganzhi-cyclic     .default:n = { true } ,
    arabicsep          .tl_set:N = \l_@@_arabic_sep_tl
  }
\str_new:N \l_@@_encoding_str
\msg_new:nnnn { zhnumber } { encoding-invalid }
  { The~encoding~`#1'~is~invalid. }
  { Available~encodings~are~`UTF8',~`GBK'~and~`Big5'. }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\zhnumsetup}
% 在文档中设置 \pkg{zhnumber} 的接口。
%    \begin{macrocode}
\NewDocumentCommand \zhnumsetup { +m }
  {
    \keys_set:nn { zhnum / options } {#1}
    \tex_ignorespaces:D
  }
%    \end{macrocode}
% \end{macro}
%
% 初始化设置和执行宏包选项。
%    \begin{macrocode}
\keys_set:nn { zhnum / options } { style , time , arabicsep = { ~ } }
\ProcessKeysOptions { zhnum / options }
%    \end{macrocode}
%
% 如果没有选定编码，则根据引擎自动设置编码。
%    \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 } }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \section{中文数字配置文件}
% \label{sec:zhnum-map}
%
%    \begin{macrocode}
%<*config>
%    \end{macrocode}
%
%    \begin{macrocode}
%<*!big5>
\zhnum_set_digits_map:nnn { minus } { simp } { 负 }
\zhnum_set_digits_map:nnn { minus } { trad } { 負 }
%</!big5>
%<*big5>
\zhnum_set_digits_map:nn { minus } { 負 }
%</big5>
\zhnum_set_digits_map:nn { 0 }     { 零 }
%<*!big5>
\zhnum_set_digits_map:nn { null }  { 〇 }
%</!big5>
%<*big5>
\zhnum_set_digits_map:nn { null }  { ○ }
%</big5>
\zhnum_set_digits_map:nn { 1 }     { 一 }
\zhnum_set_digits_map:nn { 2 }     { 二 }
\zhnum_set_digits_map:nn { 3 }     { 三 }
\zhnum_set_digits_map:nn { 4 }     { 四 }
\zhnum_set_digits_map:nn { 5 }     { 五 }
\zhnum_set_digits_map:nn { 6 }     { 六 }
\zhnum_set_digits_map:nn { 7 }     { 七 }
\zhnum_set_digits_map:nn { 8 }     { 八 }
\zhnum_set_digits_map:nn { 9 }     { 九 }
\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 }   { 皕 }
%<*!big5>
\zhnum_set_digits_map:nnn { dot } { simp } { 点 }
\zhnum_set_digits_map:nnn { dot } { trad } { 點 }
%</!big5>
%<*big5>
\zhnum_set_digits_map:nn { dot }   { 點 }
%</big5>
\zhnum_set_digits_map:nn { and }   { 又 }
\zhnum_set_digits_map:nn { parts } { 分之 }
%<*!big5>
\zhnum_set_digits_map:nnn { s1 }    { simp } { 万 }
\zhnum_set_digits_map:nnn { s1 }    { trad } { 萬 }
\zhnum_set_digits_map:nnn { s2 }    { simp } { 亿 }
\zhnum_set_digits_map:nnn { s2 }    { trad } { 億 }
%</!big5>
%<*big5>
\zhnum_set_digits_map:nn { s1 }    { 萬 }
\zhnum_set_digits_map:nn { s2 }    { 億 }
%</big5>
\zhnum_set_digits_map:nn { s3 }    { 兆 }
\zhnum_set_digits_map:nn { s4 }    { 京 }
\zhnum_set_digits_map:nn { s5 }    { 垓 }
\zhnum_set_digits_map:nn { s6 }    { 秭 }
\zhnum_set_digits_map:nn { s7 }    { 穰 }
%<*!big5>
\zhnum_set_digits_map:nnn { s8 }    { simp } { 沟 }
\zhnum_set_digits_map:nnn { s8 }    { trad } { 溝 }
\zhnum_set_digits_map:nnn { s9 }    { simp } { 涧 }
\zhnum_set_digits_map:nnn { s9 }    { trad } { 澗 }
%</!big5>
%<*big5>
\zhnum_set_digits_map:nn { s8 }    { 溝 }
\zhnum_set_digits_map:nn { s9 }    { 澗 }
%</big5>
\zhnum_set_digits_map:nn { s10 }   { 正 }
%<*!big5>
\zhnum_set_digits_map:nnn { s11 }   { simp } { 载 }
\zhnum_set_digits_map:nnn { s11 }   { trad } { 載 }
%</!big5>
%<*big5>
\zhnum_set_digits_map:nn { s11 }   { 載 }
%</big5>
\zhnum_set_digits_map:nn { year }  { 年 }
\zhnum_set_digits_map:nn { month } { 月 }
\zhnum_set_digits_map:nn { day }   { 日 }
%<*!big5>
\zhnum_set_digits_map:nnn { hour }  { simp } { 时 }
\zhnum_set_digits_map:nnn { hour }  { trad } { 時 }
%</!big5>
%<*big5>
\zhnum_set_digits_map:nn { hour }  { 時 }
%</big5>
\zhnum_set_digits_map:nn { minute }  { 分 }
\zhnum_set_digits_map:nn { weekday } { 星期 }
\zhnum_set_financial_map:nn { null } { 零 }
\zhnum_set_financial_map:nn { 0 }    { 零 }
\zhnum_set_financial_map:nn { 1 }    { 壹 }
\zhnum_set_financial_map:nn { 2 }    { 貳 }
%<*!big5>
\zhnum_set_financial_map:nnn { 3 }  { simp } { 叁 }
\zhnum_set_financial_map:nnn { 3 }  { trad } { 叄 }
%</!big5>
%<*big5>
\zhnum_set_financial_map:nn { 3 }    { 參 }
%</big5>
\zhnum_set_financial_map:nn { 4 }    { 肆 }
\zhnum_set_financial_map:nn { 5 }    { 伍 }
%<*!big5>
\zhnum_set_financial_map:nnn { 6 }  { simp } { 陆 }
\zhnum_set_financial_map:nnn { 6 }  { trad } { 陸 }
%</!big5>
%<*big5>
\zhnum_set_financial_map:nn { 6 }    { 陸 }
%</big5>
\zhnum_set_financial_map:nn { 7 }    { 柒 }
\zhnum_set_financial_map:nn { 8 }    { 捌 }
\zhnum_set_financial_map:nn { 9 }    { 玖 }
\zhnum_set_financial_map:nn { 10 }   { 拾 }
\zhnum_set_financial_map:nn { 100 }  { 佰 }
\zhnum_set_financial_map:nn { 1000 } { 仟 }
\zhnum_set_tiangan_map:nn { 1 }  { 甲 }
\zhnum_set_tiangan_map:nn { 2 }  { 乙 }
\zhnum_set_tiangan_map:nn { 3 }  { 丙 }
\zhnum_set_tiangan_map:nn { 4 }  { 丁 }
\zhnum_set_tiangan_map:nn { 5 }  { 戊 }
\zhnum_set_tiangan_map:nn { 6 }  { 己 }
\zhnum_set_tiangan_map:nn { 7 }  { 庚 }
\zhnum_set_tiangan_map:nn { 8 }  { 辛 }
\zhnum_set_tiangan_map:nn { 9 }  { 壬 }
\zhnum_set_tiangan_map:nn { 10 } { 癸 }
\zhnum_set_dizhi_map:nn { 1 }  { 子 }
\zhnum_set_dizhi_map:nn { 2 }  { 丑 }
\zhnum_set_dizhi_map:nn { 3 }  { 寅 }
\zhnum_set_dizhi_map:nn { 4 }  { 卯 }
\zhnum_set_dizhi_map:nn { 5 }  { 辰 }
\zhnum_set_dizhi_map:nn { 6 }  { 巳 }
\zhnum_set_dizhi_map:nn { 7 }  { 午 }
\zhnum_set_dizhi_map:nn { 8 }  { 未 }
\zhnum_set_dizhi_map:nn { 9 }  { 申 }
\zhnum_set_dizhi_map:nn { 10 } { 酉 }
\zhnum_set_dizhi_map:nn { 11 } { 戌 }
\zhnum_set_dizhi_map:nn { 12 } { 亥 }
%    \end{macrocode}
%
%    \begin{macrocode}
%</config>
%    \end{macrocode}
%
% \end{implementation}
%
% \Finale
%
\endinput
