% \iffalse meta-comment % !TEX program = XeLaTeX %<*internal> \iffalse % %<*readme> Introduction ------------ 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. It may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either version 1.3c of this license or (at your option) any later version. 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 work 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 (this file). 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. Author ------ Qing Lee Email: sobenlee@gmail.com If you are interested in the process of development you may observe http://code.google.com/p/ctex-kit/ Installation ------------ The package is supplied in dtx format and as a pre-extracted zip file, zhnumber.tds.zip. The later is most convenient for most users: simply unzip this in your local texmf directory and run texhash to update the database of file locations. If you want to unpack the dtx yourself, please ensure that the "iconv" program is installed and working properly, then running "xetex -shell-escape zhnumber.dtx" will extract the package whereas "xelatex zhnumber.dtx" will typeset the documentation. The package requires LaTeX3 support as provided in the l3kernel and l3packages bundles. Both of these are available on CTAN as ready-to-install zip files. Suitable versions are available in the latest version of MiKTeX and TeX Live (updating the relevant packages online may be necessary). To compile the documentation without error, you will need the xeCJK package and some specific Chinese Simplified fonts (TrueType or OpenType). % %<*internal> \fi \begingroup \edef\tempa{\fmtname} \edef\tempb{plain} \expandafter\endgroup \ifx\tempa\tempb \csname fi\endcsname % %<*install> \input l3docstrip.tex \keepsilent \askforoverwritefalse \preamble Copyright (C) 2012, 2014 by Qing Lee -------------------------------------------------------------------------- This work may be distributed and/or modified under the conditions of the LaTeX Project Public License, either version 1.3 of this license or (at your option) any later version. 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. \endpostamble \ifnum\shellescape=1 \else \errmessage{ Shell escape is disabled. Please use ^^J^^J xetex -shell-escape \jobname.ins(dtx)^^J} \expandafter\endbatchfile \fi \generate { \usedir{source/latex/zhnumber} \file{zhnumber.ins} {\from{\jobname.dtx}{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.txt} {\from{\jobname.dtx}{readme}} } \immediate\write18{iconv -f utf-8 -t big-5 zhnumber-big5.cfg > zhnumber-big5.temp} \immediate\write18{iconv -f utf-8 -t gbk zhnumber-gbk.cfg > zhnumber-gbk.temp} \immediate\write18{mv -f zhnumber-big5.temp zhnumber-big5.cfg} \immediate\write18{mv -f zhnumber-gbk.temp zhnumber-gbk.cfg} \endbatchfile % %<*internal> \fi % % %<*driver|package|config> %<*!config> \NeedsTeXFormat{LaTeX2e} \RequirePackage{expl3} % \GetIdInfo$Id: zhnumber.dtx 718 2014-09-13 09:13:29Z sobenlee $ %<*driver> {zhnumber source file} \ProvidesExplFile{\ExplFileName.\ExplFileExtension} % % {Typesetting numbers with Chinese glyphs} % {Chinese numerals with UTF8 encoding} % {Chinese numerals with Big5 encoding} % {Chinese numerals with GBK encoding} %\ProvidesExplPackage %\ProvidesExplFile % {\ExplFileName} % {\ExplFileName-utf8.cfg} % {\ExplFileName-big5.cfg} % {\ExplFileName-gbk.cfg} {\ExplFileDate}{2.1}{\ExplFileDescription} % %<*driver> \ExplSyntaxOff \let\ctexrevnum\ExplFileVersion \expandafter\let\csname ver@thumbpdf.sty\endcsname\fmtversion \documentclass[numbered,full,a4paper]{l3doc} \usepackage{amsmath} \usepackage{xeCJK} \usepackage{zhnumber} \usepackage{fvrb-ex} \usepackage{indentfirst} \usepackage{geometry} \geometry{includemp,hmargin={0mm,15mm},vmargin=15mm,footskip=7mm} \BeforeBeginEnvironment{SideBySideExample}{\vskip1ex\relax} \hypersetup{pdfstartview=FitH} \setlist{noitemsep,topsep=\smallskipamount} \linespread{1.1} \setmainfont{TeX Gyre Pagella} \setsansfont{CMU Sans Serif} \setmonofont[ UprightFont=* Light, BoldFont=* Bold, SlantedFont=* Light Oblique]{CMU Typewriter Text} \xeCJKDeclareCharClass{CJK}{ "25CB } \setCJKmainfont[BoldFont=Adobe Heiti Std,ItalicFont=Adobe Kaiti Std]{Adobe Song Std} \setCJKmonofont{Adobe Kaiti Std} \xeCJKsetup{PunctStyle=kaiming} \def\ctexkitrev#1{% \href{http://code.google.com/p/ctex-kit/source/detail?r=#1}{\texttt{ctex-kit} rev#1}} \makeatletter \def\LaTeX{\hologo{LaTeX}} \def\upTeX{up\!\hologo{TeX}} \def\upLaTeX{up\hologo{LaTeX}} \def\pdfLaTeX{\hologo{pdfLaTeX}} \def\LuaLaTeX{\hologo{LuaLaTeX}} \def\XeLaTeX{\hologo{XeLaTeX}} \def\TF{true\orvar{}false} \def\TTF{\defaultvar{true}\orvar false} \def\TFF{true\orvar\defaultvar{false}} \def\orvar{\textup{\textbar}} \def\defaultvar{\textbf} \def\argbrace#1{\{#1\}} \preto\MacroFont{\linespread{1}} \appto\MacroFont{\hyphenchar\font\m@ne} \preto\AltMacroFont{\linespread{1}} \appto\AltMacroFont{\hyphenchar\font\m@ne} \ExplSyntaxOn \cs_set_protected:Npn \__codedoc_special_index_aux:nnnnn #1#2#3#4#5 { \__codedoc_special_index_set:Nn \l__codedoc_index_escaped_macro_tl {#2} \str_if_eq:onTF { \@currenvir } { macrocode } { \codeline@wrindex } { \HD@target \index } { \tl_if_empty:nF { #3 #4 } { #3 \actualchar #4 \levelchar } #1 \actualchar { \token_to_str:N \verbatim@font \c_space_tl \l__codedoc_index_escaped_macro_tl } \encapchar hdclindex{\the\c@HD@hypercount}{#5} } } \ExplSyntaxOff \makeatother \def\indexname{代码索引} \IndexPrologue{% \section*{\indexname} \markboth{\indexname}{\indexname} 斜体的数字表示对应项说明所在的页码,下划线的数字表示定义所在的代码行号,而直立体的 数字表示对应项使用时所在的行号。} \begin{document} \DocInput{\jobname.dtx} \newgeometry{margin=15mm,footskip=7mm} \PrintIndex \end{document} % % \fi % % \CheckSum{1055} % \GetFileInfo{\jobname.sty} % % \title{\bfseries\pkg{zhnumber} 宏包} % \author{李清\\ \path{sobenlee@gmail.com}} % \date{\filedate\qquad\fileversion\thanks{\ctexkitrev{\ctexrevnum}.}} % \maketitle % % \begin{documentation} % % \section{简介} % \pkg{zhnumber} 宏包用于将阿拉伯数字按照中文格式输出。相比于 \pkg{CJKnumb},它提供 % 的三个格式转换命令 \tn{zhnumber},\tn{zhdigits} 和 \tn{zhnum} 都是可以适当展开的, % 可以正常使用于 |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 = \meta{GBK\orvar{}Big5\orvar{}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=2014-09-09]{\zhnum} % \begin{syntax} % \tn{zhnum} \Arg{counter} % \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=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}[added=2012-05-25]{\zhnumExtendScaleMap} % \begin{syntax} % \tn{zhnumExtendScaleMap} \oarg{character} \argbrace{\meta{character_1}, \meta{character_2}, ..., \meta{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} \argbrace{\meta{key_1}=\meta{val_1}, \meta{key_2}=\meta{val_2}, ...} % \end{syntax} % 用于在导言区或文档中,设置中文数字的输出格式。目前可以设置的 \meta{key} 如下介绍。 % \end{function} % % \begin{function}[added=2012-05-25]{time} % \begin{syntax} % time = \argbrace{\meta{Arabic}\orvar\meta{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}[updated=2012-05-25]{style} % \begin{syntax} % style = \argbrace{\meta{Simplified}\orvar\meta{Traditional}\orvar\meta{Normal}\orvar\meta{Financial}\orvar\meta{Ancient}} % \end{syntax} % 意义分别为 % % \begin{description}[font=\mdseries\ttfamily,align=right,labelsep=1em,labelindent=-1em,leftmargin=*] % \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 = \meta{\TFF} % \end{syntax} % 缺省状态下,除了 \tn{zhdigits} 外,其它的格式转换命令,将 0 映射成零,如果需要将 0 映射 % 成〇,可以使用这个选项。\strut % \end{function} % % \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 % 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$ 的大写。其它的选项同 % 字面意思,不再赘述。例如 % \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 = \meta{\TTF} % \end{syntax} % 在 \LaTeX{} 或者 \pdfLaTeX{} 下面输出汉字,传统的办法需要将汉字的首字节设置为 % 活动字符,然后再通过特殊的宏技巧来实现。因此,\pkg{zhnumber} 在载入配置文件的 % 时候,默认会将汉字的首字节设置为活动字符。禁用本选项将不会改变汉字首字节的 % 类代码。需要在本选项之后,使用 \texttt{encoding} 或者 \texttt{reset} 选项 % 才会有效果。 % \end{function} % % \begin{function}[updated=2014-09-09]{\zhnumber,\zhdigits,\zhnum} % \begin{syntax} % \tn{zhnumber} \oarg{options} \Arg{number} % \tn{zhdigits} * \oarg{options} \Arg{number} % \tn{zhnum} \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 } { 2014/08/25 } { } { \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}{\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:n { `#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_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 \tex_romannumeral:D -`0 \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 \tex_romannumeral:D -`0 \exp_after:wN \use:n \else: 1 \exp_after:wN ; \tex_romannumeral:D -`0 \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 \tex_romannumeral:D -`0 \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 \tex_romannumeral:D -`0 \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#8 \q_recursion_stop { \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 } } #8 \q_recursion_stop } \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}{\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 } % \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 \tex_romannumeral:D -`0 \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 \tex_romannumeral:D -`0 \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 \tex_romannumeral:D -`0 \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 { \zhnum_check_time:Nn \zhnum_digits_null:n {#1} \c_@@_year_tl \zhnum_check_time:Nn \zhnum_int:n {#2} \c_@@_month_tl \zhnum_check_time:Nn \zhnum_int:n {#3} \c_@@_day_tl } % \end{macrocode} % \end{macro} % % \begin{macro}{\zhtoday} % 输出当天日期。 % \begin{macrocode} \cs_new_nopar:Npn \zhtoday { \zhnum_check_time:Nn \zhnum_digits_null:V \tex_year:D \c_@@_year_tl \zhnum_check_time:Nn \zhnum_int:n \tex_month:D \c_@@_month_tl \zhnum_check_time:Nn \zhnum_int:n \tex_day:D \c_@@_day_tl } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\zhnum_check_time:Nn} % 判断是用中文数字还是用阿拉伯数组。 % \begin{macrocode} \cs_new:Npn \zhnum_check_time:Nn #1 { \bool_if:NTF \l_@@_time_bool {#1} { \int_to_arabic:n } } % \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 } \group_begin: \char_set_lccode:nn { `\; } { `\: } \tl_to_lowercase:n { \group_end: \cs_new:Npn \@@_time:ww #1 ; #2 \q_stop { \zhnum_check_time:Nn \zhnum_int:n {#1} \c_@@_hour_tl \zhnum_check_time:Nn \zhnum_int:n {#2} \c_@@_minute_tl } } % \end{macrocode} % \end{macro} % % \begin{macro}{\zhcurrtime} % 输出当前时间。 % \begin{macrocode} \cs_new_nopar:Npn \zhcurrtime { \zhnum_check_time:Nn \zhnum_int:n { \int_div_truncate:nn \tex_time:D { 60 } } \c_@@_hour_tl \zhnum_check_time:Nn \zhnum_int:n { \int_mod:nn \tex_time:D { 60 } } \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{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 } , } \clist_map_inline:nn { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 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 { 4 , 8 , 12 , 16 , 20 , 24 , 28 , 32 , 36 , 40 , 44 } { \tl_put_right:Nx \l_tmpa_tl { E#1 .tl_set:N = \exp_not:c { l_@@_ s \int_eval:n { #1 / 4 } _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, % \l_@@_cfg_map_prop, % \l_@@_cfg_map_var_prop, % \l_@@_cfg_map_finan_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} } \prop_new:N \l_@@_cfg_map_prop \prop_new:N \l_@@_cfg_map_var_prop \prop_new:N \l_@@_cfg_map_finan_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 \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_eq:NN \zhnum_assgin_const_tl:cx \tl_const:cx \AtEndOfPackage { \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_tl {#1} \tl_if_eq:NNF \l_@@_cfg_tl \l_@@_last_cfg_tl { \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_tl _prop } { \tl_set_eq:NN \l_@@_last_cfg_tl \l_@@_cfg_tl } { \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_tl _prop } #1 \l_@@_cfg_map_var_prop { g_@@_cfg_var_ \l_@@_cfg_tl _prop } #1 \l_@@_cfg_map_finan_prop { g_@@_cfg_finan_ \l_@@_cfg_tl _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 } \tl_new:N \l_@@_cfg_tl \tl_new:N \l_@@_last_cfg_tl \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{} 不适用。因此,参考 \pkg{ifuptex} 宏包,通过 \tn{kchar} % 是否为 primitive 来判断。 % \begin{macrocode} \pdftex_if_engine:TF { \str_if_eq_x:nnTF { \token_to_str:N \kchar } { \token_to_meaning:N \kchar } } { \use_i:nn } { \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 { \tl_set:Nx \l_@@_encoding_tl {#2} \tl_set:Nx #1 { \tl_to_str:N \l_@@_encoding_tl } } \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_tl } { { 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 { \tl_set:Nx \l_@@_encoding_tl {#2} \tl_set:Nx #1 { \tl_to_str:N \l_@@_encoding_tl \bool_if:NT \l_@@_active_char_bool { \tl_to_str:n { _active } } } } \cs_new_protected_nopar:Npn \zhnum_reset_config: { \zhnum_load_cfg:o { \l_@@_encoding_tl } } \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 } { \tl_set:Nx \l_@@_encoding_tl { \exp_args:No \tl_expandable_lowercase:n { \l_keys_choice_tl } } \zhnum_load_cfg:o { \l_@@_encoding_tl } } , 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 , } \tl_new:N \l_@@_encoding_tl \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 } \ProcessKeysOptions { zhnum / options } % \end{macrocode} % % 如果没有选定编码,则根据引擎自动设置编码。 % \begin{macrocode} \tl_if_empty:NT \l_@@_encoding_tl { \zhnum_if_unicode_engine:TF { \keys_set:nn { zhnum / options } { encoding = UTF8 } } { \keys_set:nn { zhnum / options } { encoding = GBK } } } % \end{macrocode} % % \begin{macrocode} % % \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> \zhnum_set_digits_map:nn { minus } { 負 } % \zhnum_set_digits_map:nn { 0 } { 零 } %<*!big5> \zhnum_set_digits_map:nn { null } { 〇 } % %<*big5> \zhnum_set_digits_map:nn { null } { ○ } % \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> \zhnum_set_digits_map:nn { dot } { 點 } % \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> \zhnum_set_digits_map:nn { s1 } { 萬 } \zhnum_set_digits_map:nn { s2 } { 億 } % \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> \zhnum_set_digits_map:nn { s8 } { 溝 } \zhnum_set_digits_map:nn { s9 } { 澗 } % \zhnum_set_digits_map:nn { s10 } { 正 } %<*!big5> \zhnum_set_digits_map:nnn { s11 } { simp } { 载 } \zhnum_set_digits_map:nnn { s11 } { trad } { 載 } % %<*big5> \zhnum_set_digits_map:nn { s11 } { 載 } % \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> \zhnum_set_digits_map:nn { hour } { 時 } % \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> \zhnum_set_financial_map:nn { 3 } { 參 } % \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> \zhnum_set_financial_map:nn { 6 } { 陸 } % \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 } { 仟 } % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % % \Finale % \endinput