% \iffalse meta-comment % !TEX program = XeLaTeX %<*internal> \iffalse % %<*readme> xeCJK is a package written for XeLaTeX which allows users to typeset CJK scripts easily. - different default fonts for CJK and other characters; - spaces automatically ignored between CJK characters; - special effects on full-width CJK punctuation; and - automatic adjustment of the space between CJK and other characters. This package is licensed in LPPL. This package consists of the file xeCJK.dtx, full-stop.map, fullwidth-stop.map, han-simp.map, han-trad.map, and the derived files xeCJK.pdf, xeCJK.sty, xeCJK.cfg, xeCJK.ins, xeCJKfntef.sty, xeCJK-listings.sty, xunicode-addon.sty, xeCJK-example-autofake.tex, xeCJK-example-fallback.tex, xeCJK-example-subCJKblock.tex, xeCJK-example-CJKecglue.tex, xeCJK-example-checksingle.tex, xeCJK-example-CJKfntef.tex, xeCJK-example-punctstyle.tex, xeCJK-example-verbatim.tex, xeCJK-example-IVS.tex, xeCJK-example-listings.tex, full-stop.tec, fullwidth-stop.tec, han-simp.tec, han-trad.tec, and README.txt (this file). If you are interested in the process of development you may observe http://code.google.com/p/ctex-kit/updates/list Author: Wenchang Sun Current Maintainers: Leo Liu Qing Lee Installation ------------ The package is supplied in dtx format and as a pre-extracted zip file, xecjk.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, running "xetex xeCJK.dtx" will extract the package whereas "xelatex xeCJK.dtx" will typeset the documentation. The package requires LaTeX3 support as provided in the l3kernel and l3packages bundles and the fontspec package. All 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 some specific CJK scripts 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 $Id: xeCJK.dtx 477 2013-07-25 22:15:20Z sobenlee $ $URL: https://ctex-kit.googlecode.com/svn/trunk/xeCJK/xeCJK.dtx $ ----------------------------------------------------------------- Author: Wenchang Sun Current Maintainers: Leo Liu Qing Lee Copyright (C) 2007--2013 Wenchang Sun (C) 2009--2013 Leo Liu (C) 2012--2013 Qing Lee This file 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 are Leo Liu and Qing Lee. ----------------------------------------------------------------- \endpreamble \postamble This package consists of the file xeCJK.dtx, full-stop.map, fullwidth-stop.map, han-simp.map, han-trad.map, and the derived files xeCJK.pdf, xeCJK.sty, xeCJK.cfg, xeCJK.ins, xeCJKfntef.sty, xeCJK-listings.sty, xunicode-addon.sty, xeCJK-example-autofake.tex, xeCJK-example-fallback.tex, xeCJK-example-subCJKblock.tex, xeCJK-example-CJKecglue.tex, xeCJK-example-checksingle.tex, xeCJK-example-CJKfntef.tex, xeCJK-example-punctstyle.tex, xeCJK-example-verbatim.tex, xeCJK-example-IVS.tex, xeCJK-example-listings.tex, full-stop.tec, fullwidth-stop.tec, han-simp.tec, han-trad.tec, and README.txt. \endpostamble \declarepreamble\emptypreamble \endpreamble \declarepostamble\emptypostamble \endpostamble \generate{ \usedir{source/xelatex/xecjk} \file{\jobname.ins}{\from{\jobname.dtx}{install}} \usedir{tex/xelatex/xecjk} \file{\jobname.sty}{\from{\jobname.dtx}{package}} \file{xeCJKfntef.sty}{\from{\jobname.dtx}{fntef}} \file{xeCJK-listings.sty}{\from{\jobname.dtx}{listings}} \file{xunicode-addon.sty}{\from{\jobname.dtx}{xunicode}} \usepreamble\emptypreamble \usepostamble\emptypostamble \usedir{tex/xelatex/xecjk/config} \file{\jobname.cfg}{\from{\jobname.dtx}{config}} \usedir{doc/xelatex/xecjk/example} \file{\jobname-example-autofake.tex}{\from{\jobname.dtx}{ex-autofake}} \file{\jobname-example-fallback.tex}{\from{\jobname.dtx}{ex-fallback}} \file{\jobname-example-subCJKblock.tex}{\from{\jobname.dtx}{ex-block}} \file{\jobname-example-CJKecglue.tex}{\from{\jobname.dtx}{ex-ecglue}} \file{\jobname-example-checksingle.tex}{\from{\jobname.dtx}{ex-single}} \file{\jobname-example-CJKfntef.tex}{\from{\jobname.dtx}{ex-fntef}} \file{\jobname-example-punctstyle.tex}{\from{\jobname.dtx}{ex-punctstyle}} \file{\jobname-example-verbatim.tex}{\from{\jobname.dtx}{ex-verb}} \file{\jobname-example-IVS.tex}{\from{\jobname.dtx}{ex-IVS}} \file{\jobname-example-listings.tex}{\from{\jobname.dtx}{ex-listings}} \nopreamble\nopostamble \usedir{doc/xelatex/xecjk} \file{README.txt}{\from{\jobname.dtx}{readme}} } \endbatchfile % %<*internal> \fi % %<*driver|package|config|fntef|listings|xunicode> %<*!config> \NeedsTeXFormat{LaTeX2e} \RequirePackage{expl3} % \GetIdInfo$Id: xeCJK.dtx 477 2013-07-25 22:15:20Z sobenlee $ %<*driver|package> {Typesetting CJK scripts with XeLaTeX} % % {Configuration file for xeCJK package} % {xeCJK patch file for ulem/CJKfntef} % {xeCJK patch file for listings} % {addon file for xunicode} %<*driver|config> \ProvidesExplFile % %<*driver> {\ExplFileName.\ExplFileExtension} % % {\ExplFileName.cfg} %\ProvidesExplPackage % {\ExplFileName} % {xeCJKfntef} % {xeCJK-listings} % {xunicode-addon} {\ExplFileDate}{3.2.5}{\ExplFileDescription} %<*driver> \def\xeCJKversion{3.2.5} \let\xeCJKdate\ExplFileDate \let\xeCJKrevnum\ExplFileVersion \ExplSyntaxOff % % % %<*driver> \expandafter\let\csname ver@thumbpdf.sty\endcsname\fmtversion \documentclass[numbered,a4paper,full]{l3doc} \hypersetup{pdfstartview=FitH} \usepackage{xeCJK} \usepackage{xeCJKfntef} \usepackage{geometry} \usepackage[toc]{multitoc} \fvset{formatcom=\xeCJKVerbAddon} \linespread{1.1} \setlist{noitemsep,topsep=1ex} \newlist{optiondesc}{description}{3} \setlist[optiondesc]{font=\mdseries\ttfamily,align=right,labelsep=.5em,leftmargin=4.5em} \def\PSKeyVal#1#2{\item[#1]\makebox[4em][l]{\meta{#2}}\ignorespaces} \setmainfont[Ligatures=TeX]{TeX Gyre Pagella} \setmonofont{CMU Typewriter Text} \setCJKmainfont[BoldFont=Adobe Heiti Std,ItalicFont=Adobe Kaiti Std]{Adobe Song Std} \setCJKmonofont{Adobe Kaiti Std} \xeCJKDeclareSubCJKBlock{HKMD} { "FF65 } \xeCJKDeclareSubCJKBlock{Ext-B} { "20000 -> "2A6DF } \xeCJKDeclareSubCJKBlock{Hangul}{ "1100 -> "11FF, "3130 -> "318F, "A960 -> "A97F, "AC00 -> "D7AF } \setCJKmainfont[HKMD]{Microsoft YaHei} \setCJKmainfont[Ext-B]{SimSun-ExtB} \setCJKmainfont[Hangul]{Adobe Myungjo Std} \xeCJKsetup{PunctStyle=kaiming,KaiMingPunct+={:;}} \def\MacroFont{\small\linespread{1}\normalfont\ttfamily} \def\XeTeX{\hologo{XeTeX}} \def\XeLaTeX{\hologo{XeLaTeX}} \def\LaTeX{\hologo{LaTeX}} \def\LaTeXe{\hologo{LaTeX2e}} \parindent=2em \AtBeginDocument{\DeleteShortVerb{\"}\MakeShortVerb{\|}} \def\contentsname{目录} \DeclareUrlCommand\email{\def\UrlLeft##1\UrlRight{\href{mailto:##1}{##1}}} \def\ctexkit{\href{http://code.google.com/p/ctex-kit/}{\texttt{ctex-kit}}} \def\ctexkitrev#1{% \href{http://code.google.com/p/ctex-kit/source/detail?r=#1} {\texttt{ctex-kit} rev#1}} \ExplSyntaxOn \cs_new_nopar:Npn \package #1 { \href { http://mirrors.ctan.org/help/Catalogue/entries/ \tl_expandable_lowercase:n {#1} .html } { \pkg {#1} } } \NewDocumentCommand \PrintPunctList { O{7} m m } { \par \begingroup \CJKfontspec{Microsoft~YaHei} \tl_clear:N \l_tmpa_tl \int_zero:N \l_tmpa_int \int_set:Nn \l_tmpb_int { \clist_count:c { c__xeCJK_#2_chars_clist } } \clist_map_inline:cn { c__xeCJK_#2_chars_clist } { \int_incr:N \l_tmpa_int \tl_put_right:Nx \l_tmpa_tl { \use_none:n ##1 & \tex_char:D ##1 \scan_stop: \int_compare:nNnF \l_tmpa_int = \l_tmpb_int { \int_compare:nNnTF { \int_mod:nn \l_tmpa_int {#1} } = \c_zero { \exp_not:N \\ \scan_stop: } { & } } } } \noindent\hfill\linespread{1}\selectfont \begin{tabular}{|*{#1}{>{\footnotesize\ttfamily U+}c|c|}} \tl_use:N \l_tmpa_tl \end{tabular}\hfill\null \endgroup \par } \ExplSyntaxOff \geometry{includemp,hmargin={0mm,15mm},vmargin=15mm,footskip=7mm} \makeatletter \preto\IndexParms{\linespread{1}} \appto\GlossaryParms{% \def\@idxitem{\par\hangindent 2em}% \def\subitem{\@idxitem\hspace*{1em}}% \def\subsubitem{\@idxitem\hspace*{2em}}} \patchcmd\changes@{\space}{\lbrack}{}{} \patchcmd\@wrglossary{hdpindex}{hdclindex{\the\c@HD@hypercount}}{}{} \let\orig@meta\meta \def\meta#1{% \orig@meta{\mbox{\itshape\xeCJKsetup{PunctStyle=plain,CJKecglue}#1}}} \def\TF{true\orvar{}false} \def\TTF{\defaultvar{true}\orvar{}false} \def\TFF{true\orvar\defaultvar{false}} \def\orvar{\textup{\textbar}} \def\defaultvar#1{\textbf{\textup{#1}}} \@addtoreset{CodelineNo}{section} \def\gobblelineno{% \addtocounter{CodelineNo}{\m@ne}\let\theCodelineNo\relax} \def\tokslink#1{\hyperlink{#1}{\ding{51}}} \makeatother \def\indexname{代码索引} \def\glossaryname{版本历史} \GlossaryPrologue{% \addtocounter{secnumdepth}{-10}% \section{\glossaryname}} \IndexPrologue{% \section{\indexname}% 斜体的数字表示对应项说明所在的页码,下划线的数字表示定义所在的代码行号,而直立体的 数字表示对应项使用时所在的行号。} \begin{document} \DocInput{\jobname.dtx} \newgeometry{margin=15mm,footskip=7mm} \PrintChanges \PrintIndex \end{document} % % \fi % % \CheckSum{5213} % \changes{v3.1.0}{2012/11/13}{放弃对 \cs{outer} 宏的特殊处理。} % \changes{v3.1.1}{2012/12/07}{不再依赖 \pkg{xpatch} 宏包。} % \changes{v3.2.2}{2013/06/01}{修正某些重音不能正确显示的问题。} % \changes{v3.2.3}{2013/06/07}{提供四个 TECkit 映射文件用于句号转换和简繁互换。} % \changes{v3.2.4}{2013/07/02}{遵循 \hologo{LaTeX3} 变量需要预先声明的原则。} % % % \title{\bfseries\pkg{xeCJK} 宏包} % \author{\href{http://www.ctex.org}{ctex.org}} % \date{\xeCJKdate\qquad\xeCJKversion\thanks{\ctexkitrev{\xeCJKrevnum}.}} % \maketitle % % \tableofcontents % \vspace{\baselineskip} % % \begin{documentation} % % \section{简介} % % \pkg{xeCJK} 是一个 \XeLaTeX 宏包,用于排版中日韩(CJK)文字。主要功能: % \begin{enumerate}[labelindent=\parindent,leftmargin=*] % \item 分别设置 CJK 和英文字体; % \item 自动忽略 CJK 文字间的空格而保留其它空格,允许在非标点汉字和英文 % 字母 (a -- z, A -- Z) 间断行; % \item 提供多种标点处理方式: 全角式、半角式、开明式、行末半角式和 CCT 式; % \item 自动调整中英文间空白。 % \end{enumerate} % % \pkg{xeCJK} 使用了 \XeTeX 的一些最新特性,需要 \XeTeX{} |0.9995.0 [2009/06/29]| 以 % 后的版本。\pkg{xeCJK} 依赖 \hologo{LaTeX3} 项目的宏包套件 \package{l3kernel} 和 % \package{l3packages}。\pkg{xeCJK} 还需要通过 \package{fontspec} 宏包来调用系统字 % 体。将在 \ref{subsec:opts}~节介绍的功能选项 |indentfirst| 选项需要 % \package{indentfirst} 宏包的支持。\pkg{xeCJK} 会自动根据需要载入这些宏包。 % % \pkg{xeCJK} 的原始作者是孙文昌,2009 年 5 月起宏包被收入 \ctexkit\ 项目进行 % 维护,目前主要维护者是刘海洋\footnote{\email{leoliu.pku@gmail.com}} 和 % 李清\footnote{\email{sobenlee@gmail.com}}。 % % \section{基本用法} % % 与其他 \LaTeX{} 宏包一样,引入 \pkg{xeCJK} 宏包只要在导言区使用 % \begin{verbatim} % \usepackage{xeCJK} % \end{verbatim} % 在引入 \pkg{xeCJK} 宏包之后,只要设置 CJK 文字的字体,就可以在文档中使用中日 % 韩文字了。 % % 可以在各种文档类中使用 \pkg{xeCJK} 宏包,最简单的示例是: % \begin{verbatim} % \documentclass{article} % \usepackage{xeCJK} % \setCJKmainfont{SimSun} % % \begin{document} % 中文 \LaTeX 示例。 % \end{document} % \end{verbatim} % 上述示例设置了中文字体 SimSun(宋体)。运行此示例要求系统安装了设置的字体, % 源文件用 UTF-8 编码保存,使用 \XeLaTeX{} 编译。 % % \pkg{xeCJK} 只提供了字体和标点控制等基本 CJK 语言支持。对于中文文档,可以使 % 用更为高层的 \package{ctex} 宏包或文档类,它将自动调用 \pkg{xeCJK} 并设置好中文 % 字体,同时提供了进一步的本地化支持。详细内容参看 \package{ctex} 宏包套件的说明。 % % \pkg{xeCJK} 提供了大量选项,可以在宏包调用时作为宏包选项或用 \cs{xeCJKsetup} % 命令进行设置,详见 \ref{subsec:opts}~节。除了 \cs{setCJKmainfont} 命令, % \pkg{xeCJK} 还提供了许多其他命令设置和选择中文字体,详见 % \ref{subsec:fontset}~节。其他更详细的功能也都将在下面详细说明。在本文档所在的 % 文件夹的 |example| 目录下面也有一些例子可以参考。 % % \section{用户手册} % % \subsection{宏包选项} % \label{subsec:opts} % % \pkg{xeCJK} 以 \meta{key}|=|\meta{var} 的形式提供宏包选项,你可以在调用宏包 % 的时候直接设置这些选项,也可以在调用宏包之后使用 \cs{xeCJKsetup} 来设置这些选 % 项。\pkg{xeCJK} 内部调用 \pkg{fontspec} 宏包,可以在调用 \pkg{xeCJK} 的时候, % 使用它的宏包选项。\pkg{xeCJK} 会将 \pkg{fontspec} 的选项传递给它。 % % \begin{function}{\xeCJKsetup} % \begin{syntax} % \cs{xeCJKsetup} \{\meta{key_1}=\meta{var_1}, \meta{key_2}=\meta{var_2}, ...\} % \end{syntax} % 其中 \meta{key_1}, \meta{key_2} 是设置选项,而 \meta{val_1}, \meta{val_2} 则是对应选项的 % 设置内容。多个选项可以在一个语句中完成设置。例如 % \begin{verbatim} % \usepackage[PunctStyle=kaiming]{xeCJK} % \end{verbatim} % 等价于 % \begin{verbatim} % \usepackage{xeCJK} % ...... % \xeCJKsetup{PunctStyle=kaiming} % \end{verbatim} % \end{function} % % 有些选项或命令后面带有 \hypertarget{expstar}{\hyperlink{expstar}{$\star$}} 号,这表示这 % 个选项或命令只能在导言区中使用,而 \hypertarget{rexpstar}{\hyperlink{rexpstar}{\ding{73}}} % 号则表示这个选项或命令只能在导言区使用,并且只影响随后定义的 CJK 字体。其余不带特殊标记的 % 选项或命令,如果没有特别说明,可以在导言区或正文中使用。% % 使用粗体来表示 \pkg{xeCJK} 的默认设置。 % % \begin{function}[EXP,added=2012-11-22]{LocalConfig} % \begin{syntax} % LocalConfig = \marg{\TTF\orvar{}name} % \end{syntax} % 是否使用本地配置文件 \texttt{xeCJK-\meta{name}.cfg}。\meta{name} 可以是不包含 % 空格的任意使文件名合法的字符串。如果设置为 |true|,则使用的是 \texttt{xeCJK.cfg}; % 设置为 |false| 则不载入配置文件。可以把将要在下文介绍到的对 \pkg{xeCJK} 的一些 % 设置(例如设置常用 CJK 字体、修改字符范围和定义新的标点输出格式等)保存到文件 % \texttt{xeCJK-\meta{name}.cfg}。然后把这个文件放在本地的 |TDS| 目录下的适当 % 位置。使用 \TeX~Live 的用户,可以新建下列目录,然后再把 % \texttt{xeCJK-\meta{name}.cfg} 放在里面: % \begin{verbatim} % texlive/texmf-local/tex/xelatex/xecjk % \end{verbatim} % 最后还需要在命令行下执行 |mktexlsr|,刷新文件名数据库以便 \TeX 系统能够找到它。 % \end{function} % % \begin{function}[EXP,updated=2012-11-22]{indentfirst} % \begin{syntax} % indentfirst = \meta{\TTF} % \end{syntax} % 是否使用 \pkg{indentfirst} 宏包,使得跟在章节标题后面的第一段首行也缩进。\bigskip % \end{function} % % 请注意,\pkg{xeCJK} 宏包中只有上述 |LocalConfig|、和 |indentfirst| 这两个选项需要 % 在调用 \pkg{xeCJK} 时设置,而不能通过 \cs{xeCJKsetup} 来设置。 % % \begin{function}{xeCJKactive} % \begin{syntax} % xeCJKactive = \meta{\TTF} % \end{syntax} % 打开/关闭对中文的特殊处理。事实上,这个选项会打开/关闭 \XeTeX 的整个字符类机制,依赖 % 这个机制的宏包都会受到影响。 % \end{function} % % \begin{function}{CJKspace} % \begin{syntax} % CJKspace = \meta{\TFF} % \end{syntax} % 缺省状态下,\pkg{xeCJK} 会忽略 CJK 文字之间的空格,使用这一选项来保留它们之间的空格。 % \end{function} % % \begin{function}[EXP]{CJKmath} % \begin{syntax} % CJKmath = \meta{\TFF} % \end{syntax} % 是否支持在数学环境中直接输入 CJK 字符。使用这个选项后,可以直接在数学环境中 % 输出 CJK 字符。 % \end{function} % % \begin{function}{CJKglue} % \begin{syntax} % CJKglue = \{\cs{hskip} 0pt plus 0.08\cs{baselineskip}\} % \end{syntax} % 设置 CJK 文字之间插入的 |glue|,上边是 \pkg{xeCJK} 的默认值。一般来说,除非有 % 特殊需要(例如,改变文字间距等),否则不需要设置这个选项,使用默认值即可。如果要设置 % 这个选项,为了行末的对齐,设置的 |glue| 最好有一定的弹性。 % \end{function} % % \begin{function}{CJKecglue} % \begin{syntax} % CJKecglue = \Arg{glue} % \end{syntax} % 设置 CJK 文字与西文、CJK 文字与行内数学公式之间的间距,默认值是一个空格。使用这个 % 选项设置的 |glue| 最好也要用一定的弹性。请注意,这里设置的 |glue| 只影响 % \pkg{xeCJK} 根据需要自动添加的空白,源文件中直接输入的 CJK 文字与西文之间的空格不 % 受影响(直接输出)。有时候 \pkg{xeCJK} 可能不能正确地调整间距,需要手动加空格。 % \end{function} % % \begin{function}{xCJKecglue} % \begin{syntax} % xCJKecglue = \marg{\TFF\orvar{}glue} % \end{syntax} % 缺省状态下,\pkg{xeCJK} 不对源文件中直接输入的 CJK 文字与西文之间的空格进行调整,如 % 果需要调整,请使用这个选项。如果使用这个选项,将使用 |CJKecglue| 替换源文件中直接输 % 入的 CJK 文字与西文之间的空格。 % \end{function} % % \begin{function}[updated=2013-06-26]{CheckSingle} % \begin{syntax} % CheckSingle = \meta{\TFF} % \end{syntax} % 是否避免单个 CJK 文字单独占一个段落的最后一行。需要说明的是,这个选项只有在 % 段末的最后一个字是 CJK 文字或者标点符号,并且倒数第二和第三个字都是文字才能 % 正确处理处理孤字的问题。如果这倒数三个字有作为控制序列的参数的情况,那么一般 % 来说也不能正确处理。 % \end{function} % % \begin{function}[added=2012-12-06]{PlainEquation} % \begin{syntax} % PlainEquation = \meta{\TFF} % \end{syntax} % 如果使用了 |$$...$$| 的形式来输入行间数学公式,就需要启用本选项,以便 % |CheckSingle| 选项能够正确识别。推荐使用 |\[...\]| 的形式来输入行间数学公式。 % \end{function} % % \begin{function}[added=2012-12-04]{NewLineCS,NewLineCS+,NewLineCS-} % \begin{syntax} % NewLineCS = \{ \cs{par} \cs{[} \} % \end{syntax} % 设置造成断行的控制序列,以便 |CheckSingle| 选项能够正确识别。 % 以上是 \pkg{xeCJK} 的初始设置。 % \end{function} % % \begin{function}[added=2012-12-04]{EnvCS,EnvCS+,EnvCS-} % \begin{syntax} % EnvCS = \{ \cs{begin} \cs{end} \} % \end{syntax} % 设置 \LaTeX 环境开始和结束的控制序列,以便 |CheckSingle| 选项能够正确识别。 % 以上是 \pkg{xeCJK} 的初始设置。 % \end{function} % % \begin{function}[updated=2012-12-06]{InlineEnv,InlineEnv+,InlineEnv-} % \begin{syntax} % InlineEnv = \{\meta{env_1}, \meta{env_2}, \meta{env_3}, ...\} % \end{syntax} % 在使用 |CheckSingle| 选项的时候,\pkg{xeCJK} 会将 CJK 文字后接着的 \LaTeX 环境的 % 开始 |\begin{...}| 和结束 |\end{...}| 视为断行的地方,如果有某些特殊 % 的 \LaTeX 环境没有造成断行,可以使用这个选项来声明它,以便 |CheckSingle| 能正确识别。 % \end{function} % % \begin{function}{AutoFallBack} % \begin{syntax} % AutoFallBack = \meta{\TFF} % \end{syntax} % 当文档中有个别生僻字时,可以使用这个选项,自动使用预先设置好的后备字体来输出这些生僻 % 字。后备字体的设置方法将在 \ref{subsec:fontset} 节中介绍。 % \end{function} % % \begin{function}[rEXP]{AutoFakeBold} % \begin{syntax} % AutoFakeBold = \marg{\TFF\orvar{}数字} % \end{syntax} % 全局设定当没有声明对应的粗体时,是否使用\textbf{\CJKfontspec[AutoFakeBold]{Adobe Song Std}伪粗体}; % 当输入的是数字时,将使用伪粗体,并将使用输入的数字作为伪粗体的默认粗细程度。 % \end{function} % % \begin{function}[rEXP]{AutoFakeSlant} % \begin{syntax} % AutoFakeSlant = \marg{\TFF\orvar{}数字} % \end{syntax} % 全局设定当没有声明对应的斜体时,是否使用\textit{\CJKfontspec[AutoFakeSlant]{Adobe Song Std}伪斜体}; % 当输入的是数字时,将使用伪斜体,并将使用输入的数字作为伪斜体的默认倾斜程度。 % \end{function} % % \begin{function}[rEXP]{EmboldenFactor} % \begin{syntax} % EmboldenFactor = \marg{数字\orvar\defaultvar{4}} % \end{syntax} % 设置伪粗体的默认粗细程度。 % \end{function} % % \begin{function}[rEXP]{SlantFactor} % \begin{syntax} % SlantFactor = \marg{数字\orvar\defaultvar{0.167}} % \end{syntax} % 设置伪斜体的粗细程度,范围是 $-0.999 \sim 0.999$。 % \end{function} % % \begin{function}[updated=2012-11-10]{PunctStyle} % \begin{syntax} % PunctStyle = \marg{\defaultvar{quanjiao}\orvar{}banjiao\orvar{}kaiming\orvar{}hangmobanjiao\orvar{}CCT\orvar{}plain\orvar{}...} % \end{syntax} % 设置标点处理格式。\pkg{xeCJK} 中预先定义好的格式为 % \begin{description}[font=\mdseries\ttfamily,align=right,labelsep=1em,labelindent=2em,leftmargin=*] % \item[quanjiao] 全角式:所有标点占一个汉字宽度,相邻两个标点占 1.5 汉字宽度; % \item[banjiao] 半角式:所有标点占半个汉字宽度; % \item[kaiming] 开明式:句末点号用全角,其他半角; % \item[hangmobanjiao] 行末半角式:所有标点占一个汉字宽度,行首行末对齐; % \item[CCT] CCT 格式:所有标点符号的宽度略小于一个汉字宽度; % \item[plain] 原样(不调整标点间距)。 % \end{description} % 可以使用 \ref{subsec:punctstyle} 中介绍的 \cs{xeCJKDeclarePunctStyle} 定义新的标点 % 格式。 % \end{function} % % \begin{function}[EXP]{KaiMingPunct,KaiMingPunct+,KaiMingPunct-} % \begin{syntax} % KaiMingPunct = \marg{\defaultvar{ . 。? !}} % \end{syntax} % 设置开明(|kaiming|)标点处理格式时的句末点号,|KaiMingPunct| 后带的 |+| 与 |-| % 分别表示从已有的开明句末点号中增加或减少标点。 % \end{function} % % \begin{function}[EXP]{LongPunct,LongPunct+,LongPunct-} % \begin{syntax} % LongPunct = \marg{\defaultvar{ — ― ─ ‥ … }} % \end{syntax} % 设置长标点,例如破折号“——”与省略号“……”,允许在长标点前后 % 断行,但是禁止在它们之间断行。 % \end{function} % % \begin{function}[EXP]{MiddlePunct,MiddlePunct+,MiddlePunct-} % \begin{syntax} % MiddlePunct = \marg{\defaultvar{ — ― ─ · · ・ }} % \end{syntax} % 设置居中显示的标点,例如间隔号“\textbf{·}”。对于在 CJK 文字之间的居中标点, % \pkg{xeCJK} 会根据不同的标点处理格式,调整居中标点与前后文字之间的空白,保证 % 其确实居中。对于行末出现的居中标点,允许在其后面断行,但禁止在它前面断行。 % \end{function} % % \begin{function}[EXP]{PunctWidth} % \begin{syntax} % PunctWidth = \Arg{length} % \end{syntax} % 缺省状态下,\pkg{xeCJK} 会根据所选择的标点处理格式自动计算标点所占的宽度,如果对缺 % 省设置不满意,可以通过这一选项来改变它。为了使得标点所占的宽度能够适应字体大小的变化, % 这里设置的 |length| 的单位最好用 |em| 等相对距离单位,而不建议使用诸如 |pt| 之类的 % 绝对距离单位。这里的设置可用于除了 |plain| 以外的所有标点处理格式。同时,这里的 % 设置对所有的 CJK 标点都生效,如果只要设置部分标点,请使用 \ref{subsec:punct}~节的 % \cs{xeCJKsetwidth}。 % \end{function} % % \begin{function}{AllowBreakBetweenPuncts} % \begin{syntax} % AllowBreakBetweenPuncts = \meta{\TFF} % \end{syntax} % 缺省状态下,\pkg{xeCJK} 禁止在相邻 CJK 右标点和 CJK 左标点之间换行,可以使用 % 这一选项改变这一设置。 % \end{function} % % \begin{function}[added=2012-12-02]{CheckFullRight} % \begin{syntax} % CheckFullRight = \meta{\TFF} % \end{syntax} % 某些控制序列要求不能在它的前面断行。但是在缺省状态下,单个全角右标点的后面总是 % 可以断行的。因此当这些控制序列出现在全角右标点后面时,可能会出现意料之外的断行。 % 此时可以使用这个选项来避免这个情况。 % \end{function} % % \begin{function}[added=2012-12-02]{NoBreakCS,NoBreakCS+,NoBreakCS-} % \begin{syntax} % NoBreakCS = \{ \cs{footnote} \cs{footnotemark} \cs{nobreak} \} % \end{syntax} % 设置不能在全角右标点后断行的控制序列。以上是 \pkg{xeCJK} 的默认设置。如果这些 % 控制序列在文档中只出现少量几次,也可以不必使用 |CheckFullRight| 选项,而是手工 % 在这些控制序列前面加上 \ref{subsec:others}~节介绍的 \cs{xeCJKnobreak}。 % \end{function} % % \begin{function}[updated=2013-05-29]{Verb} % \begin{syntax} % Verb = \meta{\TF\orvar\defaultvar{env}\orvar{}env+} % \end{syntax} % \texttt{true} 表示在 \cs{verb} 命令或 \texttt{verbatim} 环境里不自动调整中英文 % 之间的间距。\texttt{env} 选项在 \texttt{verbatim} 环境里自动计算中西文间距和中文 % 之间的间距,以便于保持代码的对齐;\texttt{env} 选项不调整 \cs{verb} 里的间距,^^A % \texttt{env+} 选项还将正文里设置的间距应用到 \cs{verb} 里。^^A % 这个选项对使用到 \cs{verbatim@font} 命令的情形均有效,更一般的情况可以使用 % \ref{subsec:others}~节介绍的 \cs{xeCJKVerbAddon}。 % \end{function} % % \subsection{字体设置与选择} % \label{subsec:fontset} % % \begin{function}[EXP]{\setCJKmainfont} % \begin{syntax} % \cs{setCJKmainfont} \oarg{font features} \Arg{font name} % \end{syntax} % 设置正文罗马族的 CJK 字体,影响 \cs{rmfamily} 和 \cs{textrm} 的字体。后面两个 % 参数继承自 \pkg{fontspec} 宏包, \meta{font features} 表示字体属性选项, % \meta{font name} 是字体名。字体名可以是字体族名,也可以是字体的文件名,查 % 找字体名见 \ref{subsubsec:fontsearch}~节;可用的字体属性选项参见 % \pkg{fontspec} 宏包的文档。需要说明的是 \pkg{xeCJK} 修改了 |AutoFakeBold| % 和 |AutoFakeSlant| 选项,以便配合全局伪粗体和伪斜体的设定。 % \end{function} % % \begin{function}{AutoFakeBold,AutoFakeSlant} % \begin{syntax} % AutoFakeBold = \marg{\TF\orvar{}数字} % AutoFakeSlant = \marg{\TF\orvar{}数字} % \end{syntax} % 局部设置当前字体族的伪粗和伪斜属性。如果没有在局部给出这些选项,将使用全局设定。 % \end{function} % % \begin{function}[added=2013-06-07]{Mapping} % \begin{syntax} % Mapping = \marg{fullwidth-stop\orvar{}full-stop\orvar{}han-trad\orvar{}han-simp\orvar{}...} % \end{syntax} % \pkg{xeCJK} 提供了以上四个 \href{http://scripts.sil.org/teckit}{TECKit} 映射 % 文件,可以在设置字体的时候通过 \texttt{Mapping} 选项来使用它们。其中 % \texttt{fullwidth-stop} 用于将正常句号“。”转换成全角实心句号“.”, % \texttt{full-stop} 的作用相反。\texttt{han-trad} 用于将简体中文转换成繁体中文, % \texttt{han-simp} 的作用相反。需要注意的是,简繁互换都是简单机械的字字对译, % 不能做到完全准确,使用时要小心。例如简体的“发挥”和“头发”被转换成繁体的 % “發揮”和“頭發”,显然后者应作“頭髮”。也可以根据实际需要,制作新的映射文件, % 请参考 TECKit 的文档。 % \end{function} % % \begin{function}[EXP]{\setCJKsansfont} % \begin{syntax} % \cs{setCJKsansfont} \oarg{font features} \Arg{font name} % \end{syntax} % 设置正文无衬线族的 CJK 字体,影响 \cs{sffamily} 和 \cs{textsf} 的字体。 % \end{function} % % \begin{function}[EXP]{\setCJKmonofont} % \begin{syntax} % \cs{setCJKmonofont} \oarg{font features} \Arg{font name} % \end{syntax} % 设置正文等宽族的 CJK 字体,影响 \cs{ttfamily} 和 \cs{texttt} 的字体。 % \end{function} % % \begin{function}[EXP]{\setCJKfamilyfont} % \begin{syntax} % \cs{setCJKfamilyfont} \Arg{family} \oarg{font features} \Arg{font name} % \end{syntax} % 声明新的 CJK 字体族 \meta{family} 并指定字体。 % \end{function} % % \begin{function}[updated=2012-10-27]{\CJKfamily} % \begin{syntax} % \cs{CJKfamily} \Arg{family} % \cs{CJKfamily+} \Arg{family} % \cs{CJKfamily-} \Arg{family} % \end{syntax} % 用于在文档中切换 |CJK| 字体族,\meta{family} 必须预先声明。\cs{CJKfamily} 仅对 % CJK 字符类有效,\cs{CJKfamily+} 对所有字符类均有效,\cs{CJKfamily-} 对非 CJK 字 % 符类有效。当 \cs{CJKfamily+} 和 \cs{CJKfamily-} 的参数为空时,则使用当前的 |CJK| 字体族。 % \end{function} % % \begin{function}[EXP]{\newCJKfontfamily} % \begin{syntax} % \cs{newCJKfontfamily} \oarg{family} \cs{\meta{font-switch}} \oarg{font features} \Arg{font name} % \end{syntax} % 声明新的 CJK 字体族 \meta{family} 并指定字体,并定义 \cs{\meta{font-switch}},在 % 文档中可以使用它来切换 CJK 字体族。可以不必指定 \meta{family},这时候 \meta{family} % 将等于 \meta{font-switch}。事实上,\cs{newCJKfontfamily} 是 \cs{setCJKfamilyfont} 和 % \cs{CJKfamily} 的合并。例如 % \begin{verbatim} % \newCJKfontfamily[song]\songti{SimSun} % \end{verbatim} % 等价于 % \begin{verbatim} % \setCJKfamilyfont{song}{SimSun} % \newcommand*{\songti}{\CJKfamily{song}} % \end{verbatim} % \end{function} % % \begin{function}{\CJKfontspec} % \begin{syntax} % \cs{CJKfontspec} \oarg{font features} \Arg{font name} % \end{syntax} % 在文档中随机定义新的 CJK 字体族,并马上使用它。 % \end{function} % % \begin{function}[rEXP]{\defaultCJKfontfeatures} % \begin{syntax} % \cs{defaultCJKfontfeatures} \Arg{font features} % \end{syntax} % 全局设置 CJK 字体族的默认选项。例如,使用 % \begin{verbatim} % \defaultCJKfontfeatures{Scale=0.962216} % \end{verbatim} % 可以将全部 CJK 字体缩小为 |0.962216|。\pkg{xeCJK} 宏包的初始化设置是 % \begin{verbatim} % \defaultCJKfontfeatures{Script=CJK} % \end{verbatim} % \end{function} % % \begin{function}[updated=2013-06-30]{\addCJKfontfeatures} % \begin{syntax} % \cs{addCJKfontfeatures} \Arg{font features} % \cs{addCJKfontfeatures} * \Arg{font features} % \cs{addCJKfontfeatures} \oarg{block_1, block_2, ...} \Arg{font features} % \cs{addCJKfontfeatures} * \oarg{block_1, block_2, ...} \Arg{font features} % \end{syntax} % 临时增加当前使用的 CJK 字体的选项。第一条命令,仅对当前 CJK 主分区字体有效; % 第二条对主分区和其它分区的字体都有效;第三条仅对可选参数中指定的分区有效; % 第四条对主分区和可选参数中指定的分区有效。例如,使用 % \begin{verbatim} % \addCJKfontfeatures{Scale=1.1} % \end{verbatim} % 可以将文档中当前使用的 CJK 主分区字体放大为 |1.1|。 % \end{function} % % \begin{function}{\CJKrmdefault} % 保存 \cs{textrm} 和 \cs{rmfamily} 所使用的 CJK 字体族,默认值是 |rm|。 % 类似西文字体的 \cs{rmdefault}。 % \end{function} % % \begin{function}{\CJKsfdefault} % 保存 \cs{textsf} 和 \cs{sffamily} 所使用的 CJK 字体族,默认值是 |sf|。 % 类似西文字体的 \cs{sfdefault}。 % \end{function} % % \begin{function}{\CJKttdefault} % 保存 \cs{texttt} 和 \cs{ttfamily} 所使用的 CJK 字体族,默认值是 |tt|。 % 类似西文字体的 \cs{ttdefault}。 % \end{function} % % \begin{function}[updated=2013-01-01]{\CJKfamilydefault} % 保存 \cs{textnormal} 和 \cs{normalfont} 所使用的 CJK 字体族。类似西文字体的 \cs{familydefault}。 % 初始值是 \cs{CJKrmdefault}。如果没有在导言区中修改它,\pkg{xeCJK} 会在导言区 % 结束的时候根据西文字体的情况自动更新 \cs{CJKfamilydefault}。因此,在导言区里使用 % \begin{verbatim} % \renewcommand\familydefault{\sfdefault} % \end{verbatim} % 就可以将全文的 CJK 和西文默认字体都改为无衬线字体族。 % \end{function} % % \begin{function}[EXP]{\setCJKmathfont} % \begin{syntax} % \cs{setCJKmathfont} \oarg{font features} \Arg{font name} % \end{syntax} % 设置数学公式中的 CJK 字体族。如果使用了 |CJKmath| 选项,但是没有使用 % \cs{setCJKmathfont} 设置数学公式中的 CJK 字体,那么将使用 \cs{CJKfamilydefault} % 作为数学公式中的 CJK 字体。 % \end{function} % % \begin{function}[EXP]{\setCJKfallbackfamilyfont} % \begin{syntax} % \cs{setCJKfallbackfamilyfont} \Arg{family} \oarg{font features} \Arg{font name} % \end{syntax} % 设置 CJK 字体族 \meta{family} 的备用字体。例如,使用 % \begin{verbatim} % \setCJKmainfont{SimSun} % \setCJKfallbackfamilyfont{\CJKrmdefault}{SimSun-ExtB} % \end{verbatim} % 可以将 |SimSun-ExtB| 作为 |SimSun| 的备用字体。 % \end{function} % % \begin{function}{FallBack} % \begin{syntax} % FallBack = \{\oarg{font features}\Arg{font name}\} % \end{syntax} % \pkg{xeCJK} 在 \meta{font features} 里增加了 |FallBack| 这个选项。用来在声明主 % 字体的时候,同时设置备用字体。例如,上面的例子等价于: % \begin{verbatim} % \setCJKmainfont[FallBack=SimSun-ExtB]{SimSun} % \end{verbatim} % 如果 |FallBack| 的值为空,将设置的是备用字体。例如, % \begin{verbatim} % \setCJKmainfont[FallBack,AutoFakeBold,Scale=.97]{SimSun-ExtB} % \end{verbatim} % 等价于 % \begin{verbatim} % \setCJKfallbackfamilyfont{\CJKrmdefault}[AutoFakeBold,Scale=.97]{SimSun-ExtB} % \end{verbatim} % \end{function} % % \begin{function}[EXP,updated=2013-06-30]{\setCJKfallbackfamilyfont} % \begin{syntax} % \cs{setCJKfallbackfamilyfont} \Arg{family} \oarg{common font features} % \ \{ % \ \{\oarg{font features_1} \Arg{font name_1}\} , % \ \{\oarg{font features_2} \Arg{font name_2}\} , % \ ...... % \ \} % \end{syntax} % \cs{setCJKfallbackfamilyfont} 还可以用于设置多层的备用字体。例如,使用 % \begin{verbatim} % \setCJKmainfont[AutoFakeBold,AutoFakeSlant]{KaiTi_GB2312} % \setCJKfallbackfamilyfont{\CJKrmdefault}[AutoFakeSlant] % { [BoldFont=SimHei]{SimSun} , % [AutoFakeBold] {SimSun-ExtB} } % \end{verbatim} % 之后,就设置了 |SimSun| 是 |KaiTi_GB2312| 的备用字体,而 |SimSun-ExtB| 是 % |SimSun| 的备用字体。若当前字体族缺字,并没有备用字体,则尝试使用 % \cs{CJKfamilydefault} 的备用字体。 % \end{function} % % \subsubsection{\XeTeX 的字体名查找} % \label{subsubsec:fontsearch} % % 由于在 \pkg{fontspec} 宏包文档中缺少关于如何查看 \XeTeX{} 可用字体名的说明, % 这里略作说明。 % % \XeTeX{} 通常使用 fontconfig 库查找和调用字体,因此,可以用 |fc-list| 命令显 % 示可用的字体。在命令行(Windows 的“命令提示符”,Linux 的 Console)下运行以 % 下命令: % \begin{verbatim} % fc-list > fontlist.txt % \end{verbatim} % 可以将系统中所有安装的字体列表存入 \file{fontlist.txt} 文件中(可能很长)。 % % |fc-list| 命令列出的信息很多,而且在安装字体较多的 Windows 系统上的输出将非 % 常庞大,如其中可能包含: % \begin{verbatim} % Times New Roman:style=cursiva,kurzíva,kursiv,Πλάγια,Italic, % Kursivoitu,Italique,Dőlt,Corsivo,Cursief,kursywa,Itálico,Курсив, % İtalik,Poševno,nghiêng,Etzana % Times New Roman:style=Negreta cursiva,tučné kurzíva,fed kursiv, % Fett Kursiv,Έντονα Πλάγια,Bold Italic,Negrita Cursiva, % Lihavoitu Kursivoi,Gras Italique,Félkövér dőlt,Grassetto Corsivo, % Vet Cursief,Halvfet Kursiv,Pogrubiona kursywa,Negrito Itálico, % Полужирный Курсив,Tučná kurzíva,Fet Kursiv,Kalın İtalik, % Krepko poševno,nghiêng đậm,Lodi etzana % Times New Roman:style=Negreta,tučné,fed,Fett,Έντονα,Bold,Negrita, % Lihavoitu,Gras,Félkövér,Grassetto,Vet,Halvfet,Pogrubiona,Negrito, % Полужирный,Fet,Kalın,Krepko,đậm,Lodia % Times New Roman:style=Normal,obyčejné,Standard,Κανονικά,Regular, % Normaali,Normál,Normale,Standaard,Normalny,Обычный,Normálne,Navadno, % thường,Arrunta % 宋体,SimSun:style=Regular % 黑体,SimHei:style=Normal,obyčejné,Standard,Κανονικά,Regular,Normaali, % Normál,Normale,Standaard,Normalny,Обычный,Normálne,Navadno,Arrunta % \end{verbatim} % 在 \pkg{fontspec} 或 \pkg{xeCJK} 中使用的字体族名是上面列表中冒号前的部分。 % 例如可以使用 % \begin{verbatim} % \setmainfont{Times New Roman} % \setCJKmainfont{SimSun} % 或者 \setCJKmainfont{宋体} % \end{verbatim} % 来设置字体。 % % 为了方便起见,|fc-list| 命令也可以加上各种选项控制输出格式,例如如果只要列出 % 所有的中文字体的字体族名,可以用命令: % \begin{verbatim} % fc-list -f "%{family}\n" :lang=zh > zhfont.txt % \end{verbatim} % 这样就把字体列表保存在文件 \file{zhfont.txt} 中\footnote{由于汉字编码原因, % Windows 下总需要把字体列表输出的文件中防止乱码。}。这样列出的字体列表就比较 % 简明易用,如 Windows 下预装的中文字体: % \begin{verbatim} % Arial Unicode MS % FangSong,仿宋 % KaiTi,楷体 % Microsoft YaHei,微软雅黑 % MingLiU,細明體 % NSimSun,新宋体 % PMingLiU,新細明體 % SimHei,黑体 % SimSun,宋体 % \end{verbatim} % 要列出日文和韩文的字体,可以把 |:lang=zh| 选项中的 |zh| 改成 |ja| 或 |ko|。 % % \pkg{fontspec} 和 \pkg{xeCJK} 也可以使用字体的文件名访问字体。例如 Windows % 下的宋体也可以使用命令: % \begin{verbatim} % \setCJKmainfont{simsun.ttc} % \end{verbatim} % 来设置。设置字体文件名的相关选项和语法在 \pkg{fontspec} 宏包手册中叙述甚详, % 这里不再赘述。有个别字体名不规范的中文字体,\pkg{xeCJK} 宏包可能无法正确地通 % 过字体名访问,那么也可以使用这种方式设置。 % % \subsection{CJK 分区字体设置} % \label{subsec:block} % % 众所周知,CJK 文字数量极其庞大,单一的字体不可能涵盖所有的 CJK 文字。\pkg{xeCJK} 可 % 以在同一 CJK 字体族下,自动使用不同的字体输出 CJK 字符范围内不同区块里的文字。首先要 % 声明 CJK 子分区。 % % \begin{function}[EXP]{\xeCJKDeclareSubCJKBlock} % \begin{syntax} % \cs{xeCJKDeclareSubCJKBlock} \Arg{block} \Arg{block range} % \cs{xeCJKDeclareSubCJKBlock*} \Arg{block} \Arg{block range} % \end{syntax} % 其中 \meta{block range} 是逗号列表,可以是 CJK 字符的 |Unicode| 范围,也可以是单个字符 % 的 |Unicode|。例如 % \begin{verbatim} % { `中 -> `文 , "3400 -> "4DBF , "5000 -> "7000 , `汉 , `字 , "3500 } % \end{verbatim} % 的形式。需要注意的是,这里设置的 \meta{block range} 除非确实需要(例如某些特殊字体使用 % 了 |Unicode| 中的私人使用区的情况),否则不要超出源代码中预设的 % \hyperlink{CJKcharclass}{CJK 文字范围}。使用 % \begin{verbatim} % \xeCJKDeclareSubCJKBlock{SPUA}{ "E400 -> "E4DA , "E500 -> "E5E8 , "E600 -> "E6CE } % \xeCJKDeclareSubCJKBlock{Ext-B}{ "20000 -> "2A6DF } % \end{verbatim} % 就声明了 |SPUA| 和 |Ext-B| 这两个个子分区。同时在 \ref{subsec:fontset} 节介绍的 % CJK 字体设置命令的 \meta{font features} 里新建了 |SPUA| 和 |Ext-B| 这两个选项。 % 新建的这两个选项的使用方法跟 \ref{subsec:fontset} 介绍的 |FallBack| 类似。可以 % 通过它们来设置字体。\strut % \end{function} % % 例如,可以使用 % \begin{verbatim} % \setCJKmainfont[SPUA=SunmanPUA,Ext-B=SimSun-ExtB]{SimSun} % \end{verbatim} % 设置文档的主字体是 |SimSun|,|SPUA| 分区的字体是 |SunmanPUA|,而 |Ext-B| 分区 % 的字体是 |SimSun-ExtB|。 % % \cs{xeCJKDeclareSubCJKBlock} 应该在声明所有的 CJK 字体族之前使用。如果有某个 CJK 字 % 体族没有设置 \meta{block} 选项,将使用 \cs{CJKfamilydefault} 的 \meta{block} 选项 % 作为该 CJK 字体族的 \meta{block} 选项。如果希望在使用某 CJK 字体族时,不在 CJK 主 % 分区与 \meta{block} 之间切换字体,可以使用 \meta{block}|=*| 选项。带星号的命令除了 % 设置 CJK 子分区以外,还重置标点符号所属的字符类。 % % \begin{function}{\xeCJKCancelSubCJKBlock} % \begin{syntax} % \cs{xeCJKCancelSubCJKBlock} \Arg{block_1, block_2, ...} % \cs{xeCJKCancelSubCJKBlock*} \Arg{block_1, block_2, ...} % \end{syntax} % 在文档中取消对 |CJK| 分区的声明。带星号的命令还重置标点符号所属的字符类。 % \end{function} % % \begin{function}{\xeCJKRestoreSubCJKBlock} % \begin{syntax} % \cs{xeCJKRestoreSubCJKBlock} \Arg{block_1, block_2, ...} % \cs{xeCJKRestoreSubCJKBlock*} \Arg{block_1, block_2, ...} % \end{syntax} % 在文档中恢复对 |CJK| 分区的声明。带星号的命令还重置标点符号所属的字符类。 % \end{function} % % \subsection{设置 CJK 字符范围} % % \begin{function}[EXP]{\xeCJKDeclareCharClass} % \begin{syntax} % \cs{xeCJKDeclareCharClass} \Arg{class} \Arg{class range} % \cs{xeCJKDeclareCharClass*} \Arg{class} \Arg{class range} % \end{syntax} % \meta{class range} 的格式和 \ref{subsec:block} 节的 \meta{block range} 相同。 % \meta{class} 的有效值见源代码(第 \ref{sec:xeCJK-class-set} 节)。\pkg{xeCJK} 已 % 经支持 |Unicode| 中所有 CJK 文字和标点。一般来说,不要轻易改变字符类别。带星号的 % 命令除了设置字符类别以外,为了确保标点处理的正确性,还重置标点符号所属的字符类。 % \end{function} % % \begin{function}[EXP]{\xeCJKResetCharClass} % 用于恢复 \pkg{xeCJK} 对各个字符类别的初始化设置。 % \end{function} % % \begin{function}[EXP]{\xeCJKResetPunctClass} % 用于重置标点符号所属的字符类。 % \end{function} % % \begin{function}{\normalspacedchars} % \begin{syntax} % \cs{normalspacedchars} \Arg{char list} % \end{syntax} % 在 \meta{char list} 中出现的字符两端不自动添加空格,初始设置是 |/|。 % \end{function} % % \subsection{标点符号的处理} % % \pkg{xeCJK} 对标点符号的输出宽度的调整是通过调整其左边或右边的空白宽度来实现的。 % 按照目前的处理方式,对于位于左边的标点符号(如左引号),\pkg{xeCJK} 只能调整它 % 左边的空白;对于位于右边的标点符号(如右引号),\pkg{xeCJK} 只能调整它右边的空 % 白;对于居中的标点符号,则调整其左右空白,以保证其居中。 % % \subsubsection{设置特定标点符号的宽度和间距} % \label{subsec:punct} % % 这里的设置可用于除 |plain| 以外的所有标点处理格式。 % % \begin{function}[EXP]{\xeCJKsetwidth} % \begin{syntax} % \cs{xeCJKsetwidth} \Arg{标点列表} \Arg{length} % \end{syntax} % \meta{标点列表}可以是单个标点,也可以是多个标点。例如, % \begin{verbatim} % \xeCJKsetwidth{。?}{0.7em} % \end{verbatim} % 将设置句号和问号所占的宽度为 |0.7 em|。 % \end{function} % % \begin{function}[EXP]{\xeCJKsetkern} % \begin{syntax} % \cs{xeCJKsetkern} \Arg{前标点} \Arg{后标点} \Arg{length} % \end{syntax} % \pkg{xeCJK} 会根据选定的标点处理格式自动调整相邻的前后两个 |CJK| 标点符号的 % 空白宽度。如果需要对个别情况进行特殊调整,可以使用这个命令。例如, % \begin{verbatim} % \xeCJKsetkern{:}{“}{0.3em} % \end{verbatim} % 将设置冒号与左双引号之间的空白宽度为 |0.3 em|。 % \end{function} % % \subsubsection{定义标点符号处理格式} % \label{subsec:punctstyle} % % \begin{function}[EXP,added=2012-11-10]{\xeCJKDeclarePunctStyle} % \begin{syntax} % \cs{xeCJKDeclarePunctStyle} \Arg{style} \Arg{options} % \end{syntax} % 定义新的标点符号处理格式,已经存在的同名格式将被覆盖。可以设置的选项将在下面介绍。 % \end{function} % % \begin{function}[EXP,added=2012-11-10]{\xeCJKEditPunctStyle} % \begin{syntax} % \cs{xeCJKEditPunctStyle} \Arg{style} \Arg{options} % \end{syntax} % 修改已有的标点符号处理格式。\strut % \end{function} % % 下面是可以设置的标点符号格式选项。其中左边一栏是选项名称,中间是选项的输入值类 % 型,右边则是相关说明。某些选项之间是互斥的,具有优先级关系。要使下一级的选项有 % 效,则需要先禁用上一级的设置:对于 \meta{boolean} 类型的选项,将其设置为 |false|, % 对于 \meta{length} 类型的选项,将其设置为 \cs{maxdimen},而对于 \meta{real} 类型 % 的选项,将其设置为 |0|。 % % \begin{optiondesc} % \PSKeyVal{enabled-global-setting}{boolean} % 是否使用 \cs{xeCJKsetup} 的 |PunctWidth| 选项和 \cs{xeCJKsetwidth}、 % \cs{xeCJKsetkern} 的设置。默认值是 |true|。 % \end{optiondesc} % % \begin{optiondesc} % \PSKeyVal{fixed-punct-width}{length} % 设置单个标点符号的宽度。默认值是 \cs{maxdimen}。 % \PSKeyVal{fixed-punct-ratio}{real} % 设置单个标点符号的输出宽度与实际宽度的比例。默认值是 |1.0|。 % \PSKeyVal{mixed-punct-width}{length} % 设置句末标点符号的宽度。其中句末标点符号通过 \cs{xeCJKsetup} 的 |KaiMingPunct| % 来设置。默认值是与 |fixed-punct-width| 选项的值相同。 % \PSKeyVal{mixed-punct-width}{real} % 设置句末标点符号的宽度比例。默认值是与 |fixed-punct-ratio| 选项的值相同。 % \PSKeyVal{middle-punct-width}{length} % 设置居中标点符号的宽度。其中居中标点符号通过 \cs{xeCJKsetup} 的 |MiddlePunct| % 来设置。默认值是与 |fixed-punct-width| 选项的值相同。 % \PSKeyVal{middle-punct-width}{real} % 设置居中标点符号的宽度比例。默认值是与 |fixed-punct-ratio| 选项的值相同。 % \end{optiondesc} % % 以上三个选项设置的是标点的固定宽度或比例,\pkg{xeCJK} 会根据设定的选项计算标点符号 % 左/右的空白宽度。下面的选项设置的是标点符号左/右的空白宽度或比例,因此不同标点符号 % 的宽度可能会不同。为了使下面的选项生效,需要先禁用上面的相应选项。优先级自上而下。 % % \begin{optiondesc} % \PSKeyVal{fixed-margin-width}{length} % 设置标点的左/右空白宽度。默认值是 \cs{maxdimen}。 % \PSKeyVal{fixed-margin-ratio}{real} % 设置标点的左/右空白宽度与字体中该标点的相应实际边界宽度的比例。默认值是 |1.0|。 % \PSKeyVal{mixed-margin-width}{length} % 设置句末标点的左/右空白宽度。默认值是与 |fixed-margin-width| 的值相同。 % \PSKeyVal{mixed-margin-ratio}{real} % 设置句末标点的左/右空白宽度的比例。默认值是与 |fixed-margin-ratio| 的值相同。 % \PSKeyVal{middle-margin-width}{length} % 设置居中标点的两边空白宽度。默认值是与 |fixed-margin-width| 的值相同。 % \PSKeyVal{middle-margin-ratio}{real} % 设置居中标点的两边空白宽度之和与两边实际两边边界宽度之和的比例。 % 默认值是与 |fixed-margin-ratio| 的值相同。 % \end{optiondesc} % % \begin{optiondesc} % \PSKeyVal{add-min-bound-to-margin}{boolean} % 是否在以上计算结果的基础上再加上标点的左右实际边界宽度中的最小值。这个选项 % 对居中的标点无效。默认值是 |false|。 % \end{optiondesc} % % \begin{optiondesc} % \PSKeyVal{optimize-margin}{boolean} % 使用以上设置空白宽度或比例的选项时,最终输出的标点符号左/右的空白宽度可能大 % 于原来的实际边界宽度。若此时本选项被设置为 |true|,则使用原来的实际边界宽度。 % 而使用 |fixed-punct-width| 选项计算得出的左/右宽度可能小于该标点的另一侧宽 % 度,若此时本选项被启用,则使用该标点的另一侧宽度。默认值为 |false|。 % \end{optiondesc} % % \begin{optiondesc} % \PSKeyVal{margin-minimum}{length} % 指定标点符号左/右的最小空白宽度。当经过以上选项设置的空白宽度小于这个选项的值 % 时,则使用这个选项的值。默认值是 |0 pt|。 % \end{optiondesc} % % 下面的选项处理的是前后相邻的两个标点符号之间的空白宽度。这些选项是互斥的,优先级 % 自上而下。 % % \begin{optiondesc} % \PSKeyVal{enabled-kerning}{boolean} % 是否调整前后相邻的两个标点之间的空白宽度。如果设置为 |false|,则每个标点都按 % 原来的输出宽度输出。默认值是 |true|。 % \PSKeyVal{min-bound-to-kerning}{boolean} % 是否使用当前字体中前面标点实际左右边界的最小值与后面标点实际左右边界的最小值 % 中的最大值作为两个标点之间的空白宽度。默认值是 |false|。 % \PSKeyVal{kerning-total-width}{length} % 设置两个标点的总共宽度。此时 \pkg{xeCJK} 会自动计算两个标点之间的空白宽度。 % 默认值是 \cs{maxdimen}。 % \PSKeyVal{kerning-total-ratio}{real} % 设置两个标点的总共输出宽度与实际宽度的比例。默认值是 |0.75|。 % \PSKeyVal{same-align-margin}{length} % 前后两个标点位于同侧时,它们之间的空白宽度。默认值是 \cs{maxdimen}。 % \PSKeyVal{same-align-ratio}{real} % 前后两个标点位于同侧时,它们之间的空白宽度与实际输出宽度的比例。默认值是 |0|。 % \PSKeyVal{different-align-margin}{length} % 前后两个标点位于异侧时,它们之间的空白宽度。默认值是 \cs{maxdimen}。 % \PSKeyVal{different-align-ratio}{real} % 前后两个标点位于异侧时,它们之间的空白宽度与实际输出宽度的比例。默认值是 |0|。 % \PSKeyVal{kerning-margin-width}{length} % 设置前后两个标点之间的空白宽度。默认值是 \cs{maxdimen}。 % \PSKeyVal{kerning-margin-ratio}{real} % 设置前后两个标点之间的空白宽度与实际输出空白的比例。默认值是 |1.0|。 % \end{optiondesc} % % \begin{optiondesc} % \PSKeyVal{optimize-kerning}{boolean} % 使用以上选项计算出两个标点之间的空白宽度可能小于通过 |min-bound-to-kerning| % 选项得出的结果。当出现这一情况时,若此选项被设置为 |true|,则使用该选项的空 % 白宽度。默认值为 |false|。 % \end{optiondesc} % % \begin{optiondesc} % \PSKeyVal{kerning-margin-minimum}{length} % 指定两个标点之间的最小空白宽度。当经过以上选项设置的空白宽度小于这个选项的值 % 时,则使用这个选项的值。默认值是 |0 pt|。 % \end{optiondesc} % % 事实上,\pkg{xeCJK} 的默认设置就相当于中文全角(|quanjiao|)格式。可以使用上面 % 说明的选项定义新的标点处理格式。例如,使用 % \begin{verbatim} % \xeCJKDeclarePunctStyle { mine } % { % fixed-punct-ratio = 0 , % fixed-margin-width = 0 pt , % mixed-margin-width = \maxdimen , % mixed-margin-ratio = 0.5 , % middle-margin-width = \maxdimen , % middle-margin-ratio = 0.5 , % add-min-bound-to-margin = true , % min-bound-to-kerning = true , % kerning-margin-minimum = 0.1 em % } % \end{verbatim} % 就定义了一个名为 |mine| 的标点处理格式。可以在通过 % \begin{verbatim} % \xeCJKsetup{PunctStyle=mine} % \end{verbatim} % 在文档中使用这个格式。它的意义是:使用标点符号的实际左右边界中的最小值作为其左/右 % 空白的宽度,对于句末标点和居中标点,再加上实际边界空白的一半;使用相邻两个标点的 % 实际边界中的较小值作为它们之间的空白宽度,并且最小的空白宽度是 |0.1 em|。 % 再例如,使用 % \begin{verbatim} % \xeCJKEditPunctStyle { hangmobanjiao } { enabled-global-setting = false } % \end{verbatim} % 将使得 \cs{xeCJKsetkern} 等的设置对 |hangmobanjiao| 这一格式无效。 % % \subsection{其它} % \label{subsec:others} % % \begin{function}[updated=2013-06-29]{\xeCJKVerbAddon,\xeCJKOffVerbAddon} % 调整文字间距以便于让 CJK 字符占的宽度等于西文等宽字体中两个空格的宽度。如果这两 % 个空格的宽度小于当前 CJK 正常文字的宽度,将对 CJK 字体进行适当地缩小。这有利于 % 等宽字体的代码对齐等情形。需要注意的是,\cs{xeCJKVerbAddon} 对 \pkg{xeCJK} 的内 % 部进行了比较大的修改,使用它之后,将禁止在 CJK 字符类之间自动换行,这与西文在 % 抄录环境中的情况是一致的。所以不应该单独使用,应该放在分组里限制其作用域,否则 % 是无效的。当然它可以和其它关于代码抄录的宏包配合使用。例如,可以使用于 % \package{fancyvrb} 宏包的 \texttt{formatcom} 选项。此时设置的西文字体应该确实 % 是等宽的以保证对齐。若西文等宽字体发生变动(包括字体大小),则需要在其后面使用 % \cs{xeCJKVerbAddon},重新计算间距的宽度。\cs{xeCJKOffVerbAddon} % 用于在使用 \cs{xeCJKVerbAddon} 的环境中局部取消它的作用。由于 \package{listings} % 宏包有自己的代码对齐机制,所以 \cs{xeCJKVerbAddon} 在由 \pkg{listings} 定义的 % 代码环境中无效。 % \end{function} % % \begin{function}[added=2012-12-03]{\xeCJKnobreak} % \begin{syntax} % ……汉字。\cs{xeCJKnobreak}\cs{footnote}\{脚注\} % \end{syntax} % \cs{xeCJKnobreak} 用在全角标点符号后面,目的是确保不能在此处断行。如果已经启用了 % 前面介绍的 |CheckFullRight| 选项,则不需要再用此命令。 % \end{function} % % \section{已知问题和兼容性} % % \XeTeX 在配置文件 \file{unicode-letters.tex} 中将所有 CJK 表意文字的 \cs{catcode} % 设置为 $11$。因此汉字可以直接用作控制序列的名字,但是当汉字出现在控制序列后面的 % 时候,要用空格分隔开,否则就会出现“\texttt{! Undefined control sequence.}”的错误。 % % \pkg{xeCJK} 使用并重新定义了 \pkg{CJK} 宏包的部分宏命令,如 \cs{CJKfamily}、 % \cs{CJKsymbol} 和 \cs{CJKglue} 等。需要指出,\pkg{xeCJK} 不需要 \pkg{CJK} % 的支持,并且 \pkg{xeCJK} 自动禁止在它之后载入 \pkg{CJK} 宏包。 % 可以在 \pkg{xeCJK} 之\emph{后}载入 \pkg{CJKnumb} 宏包,实现数字的中文化。 % % \CJKunderline{\pkg{xeCJK} 包含有一个子宏包 \pkg{xeCJKfntef},可以用它来实现% % \CJKunderdot{汉字加点}和可断行的下划线等。它是 \pkg{CJKfntef} 宏包在 \XeLaTeX % 下的替换版本,基本用法完全一致,在 \pkg{CJKfntef} 的源文件\ \file{CJKfntef.sty} % 的注解部分里有说明。} % % \pkg{xeCJK} 进行了一些处理,使得在使用 \XeTeX 时 \package{listings} 宏包可以 % 支持 Unicode,因此在 \texttt{listings} 定义的代码环境中可以直接使用中文,不再 % 需要通过 \texttt{escapechar}。 % % 新版本(\texttt{3.x})的 \pkg{xeCJK} 完全使用 \hologo{LaTeX3} 的语法来编写。 % \hologo{LaTeX3} 放弃了 \cs{outer} 宏的概念,因此相关工具在 % 遇到 \cs{outer} 宏时可能会存在问题。按照目前 \pkg{xeCJK} 的实现方式,在 CJK 文字 % 后面遇到 \cs{outer} 宏时会出现类似 % \begin{verbatim} % ! Forbidden control sequence found while scanning use of \use_i:nn % \end{verbatim} % 的错误。目前已知的有 \package{cprotect} 宏包提供的 \cs{cprotect}。它的定义是 % \begin{verbatim} % \outer\long\def\cprotect{\icprotect} % \end{verbatim} % 因此,这时可以暂时用 \cs{icprotect} 代替 \cs{cprotect}。事实上,当 \pkg{cprotect} % 被引入时,\pkg{xeCJK} 将使用 % \begin{verbatim} % \let\cprotect\icprotect % \end{verbatim} % 来取消 \cs{cprotect} 的外部宏限制。但由于 \cs{cprotect} 的特殊性,应该只在外部 % 使用它,即不要让它出现在任何宏的参数中。其它 \cs{outer} 宏的情况,可以在它前面 % 加上 \cs{relax} 来回避上面的错误。 % % \pkg{xeCJK} 依赖 \XeTeX 的 \cs{XeTeXinterchartoks} 机制,与使用相同机制的宏包(例如 % \pkg{polyglossia})可能会存在大小不一的冲突。\pkg{xeCJK} 虽然为此作了一些处理,但与 % 它们共同使用时应该小心。 % %\end{documentation} % % % \StopEventually{} % % %\begin{implementation} % % \section{\pkg{xeCJK} 代码实现} % % \begin{macrocode} %<*package> % \end{macrocode} % % \begin{macrocode} %<@@=xeCJK> % \end{macrocode} % % \subsection{运行环境检查} % % \pkg{xeCJK} 必须使用 \XeTeX 引擎的支持。 % \begin{macrocode} \msg_new:nnn { xeCJK } { Require-XeTeX } { The~xeCJK~package~requires~XeTeX~to~function.\\\\ You~must~change~your~typesetting~engine~to~"xelatex" \\ instead~of~plain~"latex"~or~"pdflatex"~or~"lualatex".\\ Loading~xeCJK~will~abort! } \xetex_if_engine:F { \msg_critical:nn { xeCJK } { Require-XeTeX } } % \end{macrocode} % % \begin{macro}[pTF,internal]{\xeCJK_if_package_loaded:n} % 判断宏包是否被引入,可用于文档正文中。 % \begin{macrocode} \prg_new_conditional:Npnn \xeCJK_if_package_loaded:n #1 { p , T , F , TF } { \tl_if_exist:cTF { ver@ #1 . \c_@@_package_ext_tl } { \prg_return_true: } { \prg_return_false: } } \tl_const:Nx \c_@@_package_ext_tl { \@pkgextension } % \end{macrocode} % \end{macro} % % 下面这些 \pkg{CJK} 系列宏包不应该被使用。 % \begin{macrocode} \msg_new:nnn { xeCJK } { incompatible-package } { The~`#1'~package~and~xeCJK~are~incompatible.\\\\ Please~do~not~use~it. } \msg_new:nnn { xeCJK } { after-package } { The~`#1'~package~and~xeCJK~are~incompatible.\\\\ Please~load~it~after~xeCJK. } \clist_map_inline:nn { CJKfntef , CJKnumb } { \xeCJK_if_package_loaded:nT {#1} { \msg_error:nnn { xeCJK } { after-package } {#1} } } \clist_map_inline:nn { CJKulem , CJKvert , CJKpunct , CJKutf8 , CJK } { \xeCJK_if_package_loaded:nTF {#1} { \msg_error:nnn { xeCJK } { incompatible-package } {#1} } { \tl_const:cn { ver@ #1 . \c_@@_package_ext_tl } { 9999/99/99 } } } % \end{macrocode} % % 应该使用较新版本的 \pkg{expl3} 宏包。 % \begin{macrocode} \msg_new:nnn { xeCJK } { l3-too-old } { Support~package~`#1'~too~old. \\\\ Please~update~an~up~to~date~version~of~the~bundles\\\\ `l3kernel'~and~`l3packages'\\\\ using~your~TeX~package~manager~or~from~CTAN.\\ \str_if_eq:nnT {#1} { expl3 } { Loading~xeCJK~will~abort! } } \@ifpackagelater { expl3 } { 2012/11/10 } { } { \msg_critical:nnn { xeCJK } { l3-too-old } { expl3 } } % \end{macrocode} % % 以下日期以前的 \pkg{xtemplate} 宏包关于 \cs{KeyValue} 的 Bug 会影响到后面 % 标点符号的处理。 % \begin{macrocode} \RequirePackage { xtemplate } \@ifpackagelater { xtemplate } { 2012/11/10 } { } { \msg_error:nnn { xeCJK } { l3-too-old } { xtemplate } } % \end{macrocode} % % \begin{macrocode} \RequirePackage { xparse , l3keys2e } % \end{macrocode} % % \subsection{内部工具} % % 分配临时变量。 % \begin{macrocode} \tl_new:N \l_@@_tmp_tl \int_new:N \l_@@_tmp_int \box_new:N \l_@@_tmp_box \dim_new:N \l_@@_tmp_dim \bool_new:N \l_@@_tmp_bool \skip_new:N \l_@@_tmp_skip \clist_new:N \l_@@_tmp_clist % \end{macrocode} % % \begin{macro}[internal] % {\@@_msg_new:nn ,\@@_error:n,\@@_error:nx,\@@_warning:nx,\@@_info:nxx} % 各种信息函数的缩略形式。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_msg_new:nn { \msg_new:nnn { xeCJK } } \cs_new_protected_nopar:Npn \@@_error:n { \msg_error:nn { xeCJK } } \cs_new_protected_nopar:Npn \@@_error:nx { \msg_error:nnx { xeCJK } } \cs_new_protected_nopar:Npn \@@_warning:n { \msg_warning:nn { xeCJK } } \cs_new_protected_nopar:Npn \@@_warning:nx { \msg_warning:nnx { xeCJK } } \cs_new_protected_nopar:Npn \@@_warning:nxx { \msg_warning:nnxx { xeCJK } } \cs_new_protected_nopar:Npn \@@_warning:nxxx { \msg_warning:nnxxx { xeCJK } } \cs_new_protected_nopar:Npn \@@_info:nxx { \msg_info:nnxx { xeCJK } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_allow_break:,\xeCJK_no_break:} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_allow_break: { \tex_penalty:D \c_zero } \cs_new_protected_nopar:Npn \xeCJK_no_break: { \tex_penalty:D \c_ten_thousand } % \end{macrocode} % \end{macro} % % \begin{macro}[internal] % {\@@_at_end_preamble:n,\@@_after_preamble:n,\@@_after_end_preamble:n} % 在 \cs{document} 前后加上各种钩子。 % \begin{macrocode} \tl_new:N \g_@@_at_end_preamble_hook_tl \tl_new:N \g_@@_after_preamble_hook_tl \tl_new:N \g_@@_after_end_preamble_hook_tl \cs_new_protected:Npn \@@_at_end_preamble:n #1 { \tl_gput_right:Nn \g_@@_at_end_preamble_hook_tl {#1} } \cs_new_protected:Npn \@@_after_preamble:n #1 { \tl_gput_right:Nn \g_@@_after_preamble_hook_tl {#1} } \cs_new_protected:Npn \@@_after_end_preamble:n #1 { \tl_gput_right:Nn \g_@@_after_end_preamble_hook_tl {#1} } \xeCJK_if_package_loaded:nTF { etoolbox } { \AtEndPreamble { \g_@@_at_end_preamble_hook_tl } \AfterPreamble { \g_@@_after_preamble_hook_tl } \AfterEndPreamble { \g_@@_after_end_preamble_hook_tl } } { \AtBeginDocument { \g_@@_after_preamble_hook_tl } \cs_new_protected_nopar:Npn \@@_document_left_hook: { \group_end: \g_@@_at_end_preamble_hook_tl \group_begin: } \cs_new_protected_nopar:Npn \@@_document_right_hook: { \scan_stop: \g_@@_after_end_preamble_hook_tl \tex_ignorespaces:D } \cs_gset_nopar:Npx \document { \@@_document_left_hook: \exp_not:o { \document } \@@_document_right_hook: } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_reverse:nnn} % |#1| 为 |#2| 或 |#3|,若 |#1| 和 |#2| 相等,则返回 |#3|,否则返回 |#2|。 % \begin{macrocode} \cs_new_nopar:Npn \xeCJK_reverse:nnn #1#2#3 { \str_if_eq_x:nnTF {#1} {#2} {#3} {#2} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal] % {\xeCJK_tl_remove_outer_braces:N,\xeCJK_tl_remove_outer_braces:n} % \changes{v3.2.4}{2013/07/02}{去掉外层分组括号时,移除空格,避免死循环。} % 去掉 |#1| 外层的分组括号。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_tl_remove_outer_braces:N #1 { \tl_set:Nx #1 { \exp_args:NV \xeCJK_tl_remove_outer_braces:n #1 } } \cs_new:Npn \xeCJK_tl_remove_outer_braces:n #1 { \exp_last_unbraced:Nf \@@_tl_remove_outer_braces:w { \tl_trim_spaces:n {#1} } \s__stop } \cs_new:Npn \@@_tl_remove_outer_braces:w #1 \s__stop { \bool_if:nTF { \tl_if_single_p:n {#1} && ! ( \tl_if_head_is_N_type_p:n {#1} ) } { \xeCJK_tl_remove_outer_braces:n {#1} } { \tl_trim_spaces:n {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_cs_clear:N,\xeCJK_cs_gclear:N} % 让控制序列的意义为空。 % \begin{macrocode} \cs_new_protected:Npn \xeCJK_cs_clear:N #1 { \cs_set_eq:NN #1 \prg_do_nothing: } \cs_new_protected:Npn \xeCJK_cs_gclear:N #1 { \cs_gset_eq:NN #1 \prg_do_nothing: } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_swap_cs:NN} % 交换 |#1| 和 |#2| 的意义。 % \begin{macrocode} \cs_new_protected:Npn \xeCJK_swap_cs:NN #1#2 { \cs_set_eq:NN \@@_swap_cs_aux:w #1 \cs_set_eq:NN #1 #2 \cs_set_eq:NN #2 \@@_swap_cs_aux:w \cs_undefine:N \@@_swap_cs_aux:w } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_font_gset_to_current:c} % |#1| 是控制序列的名字,令它等于当前字体命令。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_font_gset_to_current:c #1 { \exp_after:wN \cs_gset_eq:NN \cs:w #1 \exp_after:wN \cs_end: \tex_the:D \tex_font:D } % \end{macrocode} % \end{macro} % % \begin{macro}[internal,pTF]{\xeCJK_glyph_if_exist:N} % \changes{v3.1.0}{2012/11/19}{改进 \pkg{fontspec} 宏包中定义的 % \cs{font_glyph_if_exist:NnTF}。} % 判断当前字体中是否含有字符 |#1|。\pkg{fontspec} 中的类似函数在判断为真的时候, % 会留有一个 \cs{scan_stop:},造成不必要的边界,同时也不完全可展。因此,我们重新 % 定义它。 % \begin{macrocode} \prg_new_conditional:Npnn \xeCJK_glyph_if_exist:N #1 { p , T , F , TF } { \etex_iffontchar:D \tex_font:D `#1 \exp_stop_f: \prg_return_true: \else: \prg_return_false: \fi: } % \end{macrocode} % \end{macro} % % \begin{macro}[internal,var]{\c_xeCJK_space_skip_tl} % \changes{v3.1.0}{2012/11/18}{字间空格考虑 \cs{spaceskip} 不为零的情况。} % \changes{v3.2.0}{2013/05/22}{字间空格考虑到 \cs{spacefactor} 和 \cs{xspaceskip} 的情况。} % 当前字体状态下,一个字间空格产生的 |glue| 的长度,包括伸展和收缩部分。 % \begin{macrocode} \tl_const:Nn \c_xeCJK_space_skip_tl { \int_compare:nNnTF \g_@@_spacefactor_int = \c_one_thousand { \skip_if_eq:nnTF \tex_spaceskip:D \c_zero_skip { \tex_fontdimen:D \c_two \tex_font:D plus \tex_fontdimen:D \c_three \tex_font:D minus \tex_fontdimen:D \c_four \tex_font:D } { \tex_spaceskip:D } } { \skip_if_eq:nnTF \tex_spaceskip:D \c_zero_skip { \int_compare:nNnTF \g_@@_spacefactor_int < { 2000 } { \_@@_space_skip_scale:nnn { \tex_fontdimen:D \c_two \tex_font:D } } { \skip_if_eq:nnTF \tex_xspaceskip:D \c_zero_skip { \_@@_space_skip_scale:nnn { \tex_fontdimen:D \c_two \tex_font:D + \tex_fontdimen:D \c_seven \tex_font:D } } { \tex_xspaceskip:D \use_none:nn } } { \tex_fontdimen:D \c_three \tex_font:D } { \tex_fontdimen:D \c_four \tex_font:D } } { \int_compare:nNnTF \g_@@_spacefactor_int < { 2000 } { \_@@_space_skip_scale:nnn { \tex_spaceskip:D } } { \skip_if_eq:nnTF \tex_xspaceskip:D \c_zero_skip { \_@@_space_skip_scale:nnn { \tex_spaceskip:D + \tex_fontdimen:D \c_seven \tex_font:D } } { \tex_xspaceskip:D \use_none:nn } } { \etex_gluestretch:D \tex_spaceskip:D } { \etex_glueshrink:D \tex_spaceskip:D } } } } \cs_new_nopar:Npn \_@@_space_skip_scale:nnn #1#2#3 { \dim_eval:n {#1} plus \fp_eval:n { \g_@@_spacefactor_int / 1000 } #2 minus \int_div_truncate:nn { 1000 * \tex_number:D #3 } { \g_@@_spacefactor_int } sp } \int_new:N \g_@@_spacefactor_int \int_gset_eq:NN \g_@@_spacefactor_int \c_one_thousand % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_glue_to_skip:nN} % 取得一个 |glue| 的长度,包括伸展和收缩部分。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_glue_to_skip:nN #1#2 { \hbox_set:Nn \l_@@_tmp_box { #1 \scan_stop: \exp_after:wN } \exp_after:wN \skip_set:Nn \exp_after:wN #2 \exp_after:wN { \skip_use:N \tex_lastskip:D } } % \end{macrocode} % \end{macro} % % \begin{macro}[pTF,internal]{\xeCJK_if_blank_x:n} % 判断是否为空或者仅含一个空格。 % \begin{macrocode} \prg_new_conditional:Npnn \xeCJK_if_blank_x:n #1 { p , T , F , TF } { \if_case:w \pdftex_strcmp:D { } {#1} \exp_stop_f: \prg_return_true: \else: \if_case:w \pdftex_strcmp:D { ~ } {#1} \exp_stop_f: \prg_return_true: \else: \prg_return_false: \fi: \fi: } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_int_until_do:nn,\@@_int_until_do:wn} % 由于定义较为简单,可以比 \cs{int_until_do:nNnn} 稍微快一点点。 % \begin{macrocode} \cs_new_protected:Npn \xeCJK_int_until_do:nn #1#2 { \@@_int_until_do:wn \use_none:n { \reverse_if:N \if_int_compare:w #1#2 } } \cs_new_protected:Npn \@@_int_until_do:wn \use_none:n #1 { #1 \exp_after:wN \@@_int_until_do:wn \fi: \use_none:n {#1} } \int_new:N \l_@@_begin_int \int_new:N \l_@@_end_int % \end{macrocode} % % \end{macro} % % \begin{macro}[internal]{\xeCJK_peek_catcode_ignore_spaces:NTF} % \changes{v3.1.1}{2012/12/04}{新增有省略空格标识的 \texttt{peek} 函数。} % 我们在里面设置了一个变量 \cs{l_@@_peek_ignore_spaces_bool} 用于标识后面的空格 % 是否被省略掉了。 % \begin{macrocode} \cs_new_protected:Npn \xeCJK_peek_catcode_ignore_spaces:NTF #1#2#3 { \cs_set_eq:NN \l__peek_search_token #1 \scan_stop: \tl_set:Nn \@@_peek_catcode_true:w { \group_align_safe_end: #2 } \tl_set:Nn \@@_peek_catcode_false:w { \group_align_safe_end: #3 } \bool_set_false:N \l_@@_peek_ignore_spaces_bool \group_align_safe_begin: \peek_after:Nw \@@_peek_catcode_ignore_spaces_branches:w } \cs_new_protected_nopar:Npn \@@_peek_catcode_ignore_spaces_branches:w { \if_meaning:w \l_peek_token \c_space_token \bool_set_true:N \l_@@_peek_ignore_spaces_bool \exp_after:wN \peek_after:Nw \exp_after:wN \@@_peek_catcode_ignore_spaces_branches:w \tex_romannumeral:D 0 \else: \if_catcode:w \exp_not:N \l_peek_token \exp_not:N \l__peek_search_token \exp_after:wN \exp_after:wN \exp_after:wN \@@_peek_catcode_true:w \else: \exp_after:wN \exp_after:wN \exp_after:wN \@@_peek_catcode_false:w \fi: \fi: } \tl_new:N \@@_peek_catcode_true:w \tl_new:N \@@_peek_catcode_false:w \bool_new:N \l_@@_peek_ignore_spaces_bool % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_peek_after_ignore_spaces:nw} % 与 \cs{@ifnextchar} 和 \cs{futurenonspacelet} 类似,会省略掉后面的空格。 % \begin{macrocode} \cs_new_protected:Npn \xeCJK_peek_after_ignore_spaces:nw #1 { \tl_set:Nn \@@_peek_after_do:w { \group_align_safe_end: #1 } \group_align_safe_begin: \peek_after:Nw \@@_peek_ignore_spaces_branches:w } \cs_new_protected_nopar:Npn \@@_peek_ignore_spaces_branches:w { \if_meaning:w \l_peek_token \c_space_token \exp_after:wN \peek_after:Nw \exp_after:wN \@@_peek_ignore_spaces_branches:w \tex_romannumeral:D 0 \else: \exp_after:wN \@@_peek_after_do:w \fi: } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_token_value_class:N} % 用于取得记号 |#1| 所在的 \XeTeX 字符类。|#1| 应为 \cs{catcode} 为 |11| 或 |12| % 的显性或隐性记号。 % \begin{macrocode} \cs_new_nopar:Npn \xeCJK_token_value_class:N #1 { \XeTeXcharclass \xeCJK_token_value_charcode:N #1 } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_token_value_charcode:N} % \changes{v3.2.4}{2013/06/30}{考虑 \texttt{charcode} 超出 BMP 的情况。} % 当记号 |#1| 的 \texttt{charcode} 大于等于 \texttt{0x10000} 时,\XeTeX\ % \texttt{0.9999.0} 版以前的 \cs{meaning} 的返回结果比较特殊\footnote{参见 % \url{http://tug.org/pipermail/xetex/2013-January/023967.html} 和 % \url{http://tex.stackexchange.com/a/64848}。},需要特别处理。同时使用较新版本中 % 提供的原语设置 \texttt{mathcode}。目前,\texttt{0.9999.0} 版以后的 \XeTeX 的 % \cs{meaning} 对于超出 BMP 的字符,会返回两个字符,分别对应于其 UTF-16 编码的 % 首尾代理。\footnote{参见 \url{http://tug.org/pipermail/xetex/2013-June/024543.html}。} % \begin{macrocode} \cs_new_nopar:Npn \xeCJK_token_value_charcode:N #1 { \exp_after:wN \@@_token_value_charcode:w \token_to_meaning:N #1 \q_stop } \fp_compare:nNnTF { \int_use:N \xetex_XeTeXversion:D \XeTeXrevision } > { 0.9998 } { \cs_new_nopar:Npn \@@_token_value_charcode:w #1 ~ #2 ~ #3#4 \q_stop { \int_eval:n { \tl_if_empty:nTF {#4} { `#3 } { ( `#3 - "D800 ) * "400 + ( `#4 - "DC00 ) + "10000 } } } \cs_new_eq:NN \xeCJK_xetex_mathcode:w \Umathcode } { \cs_new_nopar:Npn \@@_token_value_charcode:w #1 ~ #2 ~ #3#4 \q_stop { \int_eval:n { \tl_if_empty:nTF {#4} { `#3 } { "20000 } } } \cs_new_eq:NN \xeCJK_xetex_mathcode:w \XeTeXmathcode } % \end{macrocode} % \end{macro} % % \begin{macro}[pTF,internal]{\xeCJK_if_CJK_class:N} % 判断字符 |#1| 是否为 CJK 字符类,包括文字和标点符号。 % \begin{macrocode} \prg_new_conditional:Npnn \xeCJK_if_CJK_class:N #1 { p , T , F , TF } { \if_cs_exist:w \@@_CJK_class_tl:n { \xeCJK_token_value_class:N #1 } \cs_end: \prg_return_true: \else: \prg_return_false: \fi: } \cs_new_nopar:Npn \@@_CJK_class_tl:n #1 { c_@@_CJK_class_ \int_eval:n {#1} _tl } \cs_generate_variant:Nn \@@_CJK_class_tl:n { c } % \end{macrocode} % \end{macro} % % \begin{macro}[pTF,internal]{\xeCJK_if_same_class:NN} % 判断两个字符是否同属于一个字符类。 % \begin{macrocode} \prg_new_conditional:Npnn \xeCJK_if_same_class:NN #1#2 { p , T , F , TF } { \if_int_compare:w \xeCJK_token_value_class:N #1 = \xeCJK_token_value_class:N #2 \exp_stop_f: \prg_return_true: \else: \prg_return_false: \fi: } % \end{macrocode} % \end{macro} % % \subsection{功能开关} % % \begin{macro}{xeCJKactive} % 事实上,将开启或关闭 \XeTeX 的整个字符类机制。 % \begin{macrocode} \keys_define:nn { xeCJK / options } { xeCJKactive .choice: , xeCJKactive / true .code:n = { \makexeCJKactive } , xeCJKactive / false .code:n = { \makexeCJKinactive } , xeCJKactive .default:n = { true } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\makexeCJKactive, \makexeCJKinactive} % \begin{macrocode} \NewDocumentCommand \makexeCJKactive { } { \XeTeXinterchartokenstate = \c_one } \NewDocumentCommand \makexeCJKinactive { } { \XeTeXinterchartokenstate = \c_zero } % \end{macrocode} % \end{macro} % % 抑制 |BOM|。 % \begin{macrocode} \char_set_catcode_ignore:n { "FEFF } % \end{macrocode} % % \subsection{字符类别设定}\label{sec:xeCJK-class-set} % % \begin{macro}[internal,var]{\g_@@_class_seq,\g_@@_new_class_seq} % 分别用于记录在 \pkg{xeCJK} 中使用的字符类别名称和新建的字符类别的编号。 % \begin{macrocode} \seq_new:N \g_@@_class_seq \seq_new:N \g_@@_new_class_seq % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_new_class:n} % 新建一个字符类别。|#1| 是自定义名称。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_new_class:n #1 { \int_if_exist:cTF { \@@_class_csname:n {#1} } { \@@_error:nx { class-already-defined } {#1} } { \exp_args:Nc \newXeTeXintercharclass { \@@_class_csname:n {#1} } \clist_new:c { g_@@_#1_range_clist } \seq_gput_right:Nn \g_@@_class_seq {#1} \seq_gput_right:Nv \g_@@_new_class_seq { \@@_class_csname:n {#1} } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_save_class:nn} % \changes{v3.1.1}{2012/12/06} % {使用 \cs{xeCJK_save_class:nn} 保存 \XeTeX 预定义的字符类别。} % 保存 \XeTeX 预定义的字符类别。|#1| 是自定义名称,|#2| 是编号。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_save_class:nn #1#2 { \int_if_exist:cTF { \@@_class_csname:n {#1} } { \@@_error:nx { class-already-defined } {#1} } { \int_const:cn { \@@_class_csname:n {#1} } {#2} \clist_new:c { g_@@_#1_range_clist } \seq_gput_right:Nn \g_@@_class_seq {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_class_csname:n} % 字符类名称对应的控制序列名字。 % \begin{macrocode} \cs_new_nopar:Npn \@@_class_csname:n #1 { c_@@_#1_class_int } \cs_new_eq:cN { \@@_class_csname:n { Others } } \l_@@_tmp_int \@@_msg_new:nn { class-already-defined } { XeTeX~character~class~`#1'~has~been~already~defined.\\\\ Please~take~another~name. \\ } % \end{macrocode} % \end{macro} % % \changes{v3.2.0}{2013/05/20}{增加 \texttt{IVS} 字符类用于处理异体字选择符。} % % \pkg{xeCJK} 需要以下字符类别用于字符输出。其中 |Default|、|CJK|、|FullLeft|、 % |FullRight|、|Boundary| 为 \XeTeX\ 中预定义的类别,\pkg{xeCJK} 新增加了\ % |HalfLeft|、|HalfRight|、|NormalSpace| 和 |IVS|。其中异体字选择符 % (Ideographic Variation Selectors)\footnote{\url{http://www.unicode.org/reports/tr37/}} % 需要 \XeTeX\ |0.9999.0| 以上的版本^^A % \footnote{\url{http://tug.org/pipermail/xetex/2013-March/024118.html}}和相关字体的支持。 % \begin{center}\xeCJKsetup{PunctStyle=plain} % \begin{tabular}{cll} % \toprule % 类别 & 说明 & 例子 \\ \midrule % |Default| & 西文一般符号 & abc123 \\ % |CJK| & CJK 表意符号 & 汉字ぁぃぅ \\ % |FullLeft| & 全角左标点 & (《:“ \\ % |FullRight| & 全角右标点 & ,。)》” \\ % |HalfLeft| & 半角左标点 & ( [ \{ \\ % |HalfRight| & 半角右标点 & , . ? ) ] \} \\ % |NormalSpace| & 前后原始间距的符号 & / \\ % |Boundary| & 边界 & 空格 \\ % |IVS| & 异体字选择符 & “回字有四样写法”\\ % \bottomrule % \end{tabular} % \end{center} % % \begin{macro}[internal]{Default,CJK,FullLeft,FullRight,Boundary} % 这五类是 \XeTeX\ 预定义的类别。 % \begin{macrocode} \xeCJK_save_class:nn { Default } { \c_zero } \xeCJK_save_class:nn { CJK } { \c_one } \xeCJK_save_class:nn { FullLeft } { \c_two } \xeCJK_save_class:nn { FullRight } { \c_three } \xeCJK_save_class:nn { Boundary } { \c_two_hundred_fifty_five } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{HalfLeft,HalfRight,NormalSpace,IVS} % 新增西文半角左/右标点、前后原始间距的符号和异体字选择符类。 % \begin{macrocode} \xeCJK_new_class:n { HalfLeft } \xeCJK_new_class:n { HalfRight } \xeCJK_new_class:n { NormalSpace } \xeCJK_new_class:n { IVS } % \end{macrocode} % \end{macro} % % \begin{macro}[var,internal] % {\c_@@_HalfLeft_chars_clist,\c_@@_HalfRight_chars_clist,\c_@@_NormalSpace_chars_clist} % \hypertarget{CJKcharclass}{西文半角左/右标点和前后原始间距的字符类。} % \begin{macrocode} \clist_const:Nn \c_@@_HalfLeft_chars_clist { "28 , "2D , "5B , "60 , "7B } \clist_const:Nn \c_@@_HalfRight_chars_clist { "21 , "22 , "25 , "27 , "29 , "2C , "2E , "3A , "3B , "3F , "5D , "7D } \clist_const:Nn \c_@@_NormalSpace_chars_clist { "2F } % \end{macrocode} % \end{macro} % % 以下对全角标点符号的归类来源于 \XeTeX 的脚本 % \href{http://sourceforge.net/p/xetex/code/ci/master/tree/source/texk/web2c/xetexdir/unicode-char-prep.pl} % {\file{unicode-char-prep.pl}} 和 Unicode 数据库\footnote{\url{http://www.unicode.org/reports/tr14/}}。 % % \changes{v3.2.3}{2013/06/09}{根据 \XeTeX 的脚本重新整理全角标点符号。} % % \begin{macro}[var,internal]{\c_@@_OP_chars_clist} % Open Punctuation (OP) % \PrintPunctList{OP}{Open Punctuation} % 以下代码的第一行是中西文共用的左引号。 % \begin{macrocode} \clist_const:Nn \c_@@_OP_chars_clist { "2018 , "201C , "2329 , "3008 , "300A , "300C , "300E , "3010 , "3014 , "3016 , "3018 , "301A , "301D , "FE17 , "FE35 , "FE37 , "FE39 , "FE3B , "FE3D , "FE3F , "FE41 , "FE43 , "FE47 , "FE59 , "FE5B , "FE5D , "FF08 , "FF3B , "FF5B , "FF5F , "FF62 } % \end{macrocode} % \end{macro} % % \begin{macro}[var,internal]{\c_@@_PR_chars_clist} % Prefix Numeric (PR) % \PrintPunctList{PR}{Prefix Numeric} % \begin{macrocode} \clist_const:Nn \c_@@_PR_chars_clist { "20A9 , "FE69 , "FF04 , "FFE1 , "FFE5 , "FFE6 } % \end{macrocode} % \end{macro} % % \begin{macro}[var,internal]{\c_@@_FullLeft_chars_clist} % 以上两类标点符号出现在文字的左边,不应出现在行尾位置。 % \begin{macrocode} \clist_const:Nx \c_@@_FullLeft_chars_clist { \c_@@_OP_chars_clist , \c_@@_PR_chars_clist } % \end{macrocode} % \end{macro} % % \begin{macro}[var,internal]{\c_@@_CL_chars_clist} % Close Punctuation (CL) % \PrintPunctList{CL}{Close Punctuation} % 以下代码的第一行是中西文共用的一些标点符号。 % \begin{macrocode} \clist_const:Nn \c_@@_CL_chars_clist { "00B7 , "2019 , "201D , "2014 , "2015 , "2025 , "2026 , "2027 , "2500 , "232A , "3001 , "3002 , "3009 , "300B , "300D , "300F , "3011 , "3015 , "3017 , "3019 , "301B , "301E , "301F , "FE11 , "FE12 , "FE18 , "FE36 , "FE38 , "FE3A , "FE3C , "FE3E , "FE40 , "FE42 , "FE44 , "FE48 , "FE50 , "FE52 , "FE5A , "FE5C , "FE5E , "FF09 , "FF0C , "FF0E , "FF3D , "FF5D , "FF60 , "FF61 , "FF63 , "FF64 } % \end{macrocode} % \end{macro} % % \begin{macro}[var,internal]{\c_@@_NS_chars_clist} % Nonstarter (NS) % \PrintPunctList{NS}{Nonstarter} % \begin{macrocode} \clist_const:Nn \c_@@_NS_chars_clist { "3005 , "301C , "303B , "303C , "309B , "309C , "309D , "309E , "30A0 , "30FB , "30FD , "30FE , "A015 , "FE54 , "FE55 , "FF1A , "FF1B , "FF65 , "FF9E , "FF9F } % \end{macrocode} % \end{macro} % % \begin{macro}[var,internal]{\c_@@_EX_chars_clist} % Exclamation/Interrogation (EX) % \PrintPunctList{EX}{Exclamation/Interrogation} % \begin{macrocode} \clist_const:Nn \c_@@_EX_chars_clist { "FE15 , "FE16 , "FE56 , "FE57 , "FF01 , "FF1F } % \end{macrocode} % \end{macro} % % \begin{macro}[var,internal]{\c_@@_IS_chars_clist} % Infix Numeric Separator (IS) % \PrintPunctList{IS}{Infix Numeric Separator} % \begin{macrocode} \clist_const:Nn \c_@@_IS_chars_clist { "FE10 , "FE13 , "FE14 } % \end{macrocode} % \end{macro} % % \begin{macro}[var,internal]{\c_@@_CJ_chars_clist} % Conditional Japanese Starter (CJ) % \PrintPunctList{CJ}{Conditional Japanese Starter} % \begin{macrocode} \clist_const:Nn \c_@@_CJ_chars_clist { "3041 , "3043 , "3045 , "3047 , "3049 , "3063 , "3083 , "3085 , "3087 , "308E , "3095 , "3096 , "30A1 , "30A3 , "30A5 , "30A7 , "30A9 , "30C3 , "30E3 , "30E5 , "30E7 , "30EE , "30F5 , "30F6 , "30FC , "31F0 , "31F1 , "31F2 , "31F3 , "31F4 , "31F5 , "31F6 , "31F7 , "31F8 , "31F9 , "31FA , "31FB , "31FC , "31FD , "31FE , "31FF , "FF67 , "FF68 , "FF69 , "FF6A , "FF6B , "FF6C , "FF6D , "FF6E , "FF6F , "FF70 } % \end{macrocode} % \end{macro} % % \begin{macro}[var,internal]{\c_@@_PO_chars_clist} % Postfix Numeric (PO) % \PrintPunctList{PO}{Postfix Numeric} % \begin{macrocode} \clist_const:Nn \c_@@_PO_chars_clist { "FE6A , "FF05 , "FFE0 } % \end{macrocode} % \end{macro} % % \begin{macro}[var,internal]{\c_@@_FullRight_chars_clist} % 以上六类标点符号出现在文字的右边,不应出现在行首位置。 % \begin{macrocode} \clist_const:Nx \c_@@_FullRight_chars_clist { \c_@@_CL_chars_clist , \c_@@_NS_chars_clist , \c_@@_EX_chars_clist , \c_@@_IS_chars_clist , \c_@@_CJ_chars_clist , \c_@@_PO_chars_clist } % \end{macrocode} % \end{macro} % % \begin{macro}[var,internal]{\c_@@_CJK_chars_clist} % CJK 字符类,包括文字和标点符号。 % \begin{macrocode} \clist_const:Nn \c_@@_CJK_chars_clist { % \end{macrocode} % \begin{itemize}[nosep,leftmargin=0pt] % \item Hangul Jamo (谚文字母) % \begin{macrocode} "1100 -> "11FF , % \end{macrocode} % \item CJK Radicals Supplement (中日韩部首补充) % \begin{macrocode} "2E80 -> "2EFF , % \end{macrocode} % \item Kangxi Radicals (康熙部首) % \begin{macrocode} "2F00 -> "2FDF , % \end{macrocode} % \item Ideographic Description Characters (表意文字描述符) % \begin{macrocode} "2FF0 -> "2FFF , % \end{macrocode} % \item CJK Symbols and Punctuation (中日韩符号和标点) % \begin{macrocode} "3000 -> "303F , % \end{macrocode} % \item Hiragana (日文平假名) % \begin{macrocode} "3040 -> "309F , % \end{macrocode} % \item Katakana (日文片假名) % \begin{macrocode} "30A0 -> "30FF , % \end{macrocode} % \item Bopomofo (注音字母) % \begin{macrocode} "3100 -> "312F , % \end{macrocode} % \item Hangul Compatibility Jamo (谚文兼容字母) % \begin{macrocode} "3130 -> "318F , % \end{macrocode} % \item Kanbun (象形字注释标志) % \begin{macrocode} "3190 -> "319F , % \end{macrocode} % \item Bopomofo Extended (注音字母扩展) % \begin{macrocode} "31A0 -> "31BF , % \end{macrocode} % \item CJK Strokes (中日韩笔画) % \begin{macrocode} "31C0 -> "31EF , % \end{macrocode} % \item Katakana Phonetic Extensions (日文片假名语音扩展) % \begin{macrocode} "31F0 -> "31FF , % \end{macrocode} % \item Enclosed CJK Letters and Months (带圈中日韩字母和月份) % \begin{macrocode} "3200 -> "32FF , % \end{macrocode} % \item CJK Compatibility (中日韩兼容) % \begin{macrocode} "3300 -> "33FF , % \end{macrocode} % \item CJK Unified Ideographs Extension-A (中日韩统一表意文字扩展 A) % \begin{macrocode} "3400 -> "4DBF , % \end{macrocode} % \item Yijing Hexagrams Symbols (易经六十四卦符号) % \begin{macrocode} "4DC0 -> "4DFF , % \end{macrocode} % \item CJK Unified Ideographs (中日韩统一表意文字) % \begin{macrocode} "4E00 -> "9FFF , % \end{macrocode} % \item Yi Syllables (彝文音节) % \begin{macrocode} "A000 -> "A48F , % \end{macrocode} % \item Yi Radicals (彝文字根) % \begin{macrocode} "A490 -> "A4CF , % \end{macrocode} % \item Hangul Jamo Extended-A (谚文扩展 A) % \begin{macrocode} "A960 -> "A97F , % \end{macrocode} % \item Hangul Syllables (谚文音节) % \begin{macrocode} "AC00 -> "D7AF , % \end{macrocode} % \item Hangul Jamo Extended-B (谚文扩展 B) % \begin{macrocode} "D7B0 -> "D7FF , % \end{macrocode} % \item CJK Compatibility Ideographs (中日韩兼容表意文字) % \begin{macrocode} "F900 -> "FAFF , % \end{macrocode} % \item Vertical Forms (竖排形式) % \begin{macrocode} "FE10 -> "FE1F , % \end{macrocode} % \item CJK Compatibility Forms (中日韩兼容形式) % \begin{macrocode} "FE30 -> "FE4F , % \end{macrocode} % \item Halfwidth and Fullwidth Forms (半角及全角形式) % \begin{macrocode} "FF00 -> "FFEF , % \end{macrocode} % \item Kana Supplement (日文假名增补) % \begin{macrocode} "1B000 -> "1B0FF , % \end{macrocode} % \item Enclosed Ideographic Supplement (带圈表意文字增补) % \begin{macrocode} "1F200 -> "1F2FF , % \end{macrocode} % \item CJK Unified Ideographs Extension-B (中日韩统一表意文字扩展 B) % \begin{macrocode} "20000 -> "2A6DF , % \end{macrocode} % \item CJK Unified Ideographs Extension-C (中日韩统一表意文字扩展 C) % \begin{macrocode} "2A700 -> "2B73F , % \end{macrocode} % \item CJK Unified Ideographs Extension-D (中日韩统一表意文字扩展 D) % \begin{macrocode} "2B740 -> "2B81F , % \end{macrocode} % \item CJK Compatibility Ideographs Supplement (中日韩兼容表意文字增补) % \begin{macrocode} "2F800 -> "2FA1F % \end{macrocode} % \end{itemize} % \begin{macrocode} } % \end{macrocode} % \end{macro} % % \begin{macro}[var,internal]{\c_@@_IVS_chars_clist} % 包括日文假名浊点和异体字选择符。 % \begin{macrocode} \clist_const:Nn \c_@@_IVS_chars_clist { % \end{macrocode} % \begin{itemize}[nosep,leftmargin=0pt] % \item 日文假名浊点 % \begin{macrocode} "3099 -> "309A , % \end{macrocode} % \item Variation Selectors (异体字选择符) % \begin{macrocode} "FE00 -> "FE0F , % \end{macrocode} % \item Variation Selectors Supplement (异体字选择符增补) % \begin{macrocode} "E0100 -> "E01EF % \end{macrocode} % \end{itemize} % \begin{macrocode} } % \end{macrocode} % \end{macro} % % \subsection{字符类别处理} % % \begin{macro}[internal,var] % {\g_@@_base_class_seq,\g_@@_non_CJK_class_seq,\g_@@_CJK_class_seq} % \begin{macrocode} \seq_new:N \g_@@_base_class_seq \seq_gset_eq:NN \g_@@_base_class_seq \g_@@_class_seq \seq_new:N \g_@@_non_CJK_class_seq \seq_gset_from_clist:Nn \g_@@_non_CJK_class_seq { Default , HalfLeft , HalfRight , NormalSpace , Boundary } \seq_new:N \g_@@_CJK_class_seq \cs_new_protected_nopar:Npn \@@_save_CJK_class:n #1 { \seq_gput_right:Nn \g_@@_CJK_class_seq {#1} \tl_const:cn { \@@_CJK_class_tl:c { \@@_class_csname:n {#1} } } {#1} } \clist_map_function:nN { CJK , FullLeft , FullRight , IVS } \@@_save_CJK_class:n % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_class_num:n} % |#1| 为字符类别名称,用于取得字符类别对应的编号。 % \begin{macrocode} \cs_new_nopar:Npn \xeCJK_class_num:n #1 { \use:c { \@@_class_csname:n {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}{\xeCJKDeclareCharClass} % \begin{macrocode} \NewDocumentCommand \xeCJKDeclareCharClass { s > { \TrimSpaces } m m } { \xeCJK_declare_char_class:nx {#2} {#3} \IfBooleanT {#1} { \xeCJKResetPunctClass } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_declare_char_class:nn,\@@_set_char_class_aux:Nnw} % 用于设置字符所属的类别,|#1| 为类别名称,|#2| 为字符的 |Unicode|,相邻字符用 % 半角逗号隔开,支持类似 |"1100 -> "11FF| 起止范围的使用方式。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_declare_char_class:nn #1#2 { \clist_set:Nn \l_@@_tmp_clist {#2} \clist_gconcat:ccN { g_@@_#1_range_clist } { g_@@_#1_range_clist } \l_@@_tmp_clist \clist_map_inline:Nn \l_@@_tmp_clist { \str_if_eq:nnF {##1} { -> } { \@@_set_char_class_aux:Nnw \xeCJK_set_char_class:nnn {##1} { \xeCJK_class_num:n {#1} } } } \xeCJK_set_char_class:nnn { "3099 } { "309A } { \xeCJK_class_num:n { IVS } } } \NewDocumentCommand \@@_set_char_class_aux:Nnw { m > { \SplitArgument { 1 } { -> } } m } { #1 #2 } \cs_generate_variant:Nn \clist_gconcat:NNN { cc } \cs_generate_variant:Nn \xeCJK_declare_char_class:nn { nx , nV } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_check_num_range:nnNN} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_check_num_range:nnNN #1#2#3#4 { \bool_if:nTF { \xeCJK_if_blank_x_p:n {#1} || \xeCJK_if_blank_x_p:n {#2} } { \int_set:Nn #3 { \xeCJK_if_blank_x:nTF {#1} {#2} {#1} } \int_set_eq:NN #3 #4 } { \int_set:Nn #3 { \int_min:nn {#1} { \IfNoValueTF {#2} {#1} {#2} } } \int_set:Nn #4 { \int_max:nn {#1} { \IfNoValueTF {#2} {#1} {#2} } } } } % \end{macrocode} % \end{macro} % % \changes{v3.2.3}{2013/06/08}{不再改变 CJK 字符类的 \cs{catcode}。} % % \begin{macro}[internal]{\xeCJK_set_char_class:nnn} % \changes{v3.1.1}{2012/12/05}{在文档中设置字符类别时不重复设置 \cs{catcode}。} % 设置字符类别,|#1| 和 |#2| 为字符类别起止的 |Unicode|,|#3| 为类别名称对应编号。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_set_char_class:nnn #1#2#3 { \@@_check_num_range:nnNN {#1} {#2} \l_@@_begin_int \l_@@_end_int \int_set:Nn \l_@@_tmp_int {#3} \xeCJK_int_until_do:nn { \l_@@_begin_int > \l_@@_end_int } { \XeTeXcharclass \l_@@_begin_int = \l_@@_tmp_int \int_incr:N \l_@@_begin_int } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_set_char_class_eq:nn} % \changes{v3.1.1}{2012/12/06}{交换参数的顺序。} % 将字符类 |#1| 中的字符全部设置成字符类 |#2|。只适用于 |#1| 的字符类范围为离散的 % 逗号列表的情况。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_set_char_class_eq:nn #1#2 { \int_set:Nn \l_@@_tmp_int { \xeCJK_class_num:n {#2} } \clist_map_inline:cn { c_@@_#1_chars_clist } { \XeTeXcharclass ##1 = \l_@@_tmp_int } } % \end{macrocode} % \end{macro} % % \begin{macro}{\normalspacedchars} % 声明前后不加间距的字符。 % \begin{macrocode} \NewDocumentCommand \normalspacedchars { m } { \tl_map_inline:nn {#1} { \XeTeXcharclass `##1 = \xeCJK_class_num:n { NormalSpace } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\xeCJKResetPunctClass} % 用于重置标点符号所属的字符类。 % \begin{macrocode} \NewDocumentCommand \xeCJKResetPunctClass { } { \xeCJK_declare_char_class:nV { HalfLeft } \c_@@_HalfLeft_chars_clist \xeCJK_declare_char_class:nV { HalfRight } \c_@@_HalfRight_chars_clist \xeCJK_declare_char_class:nV { FullLeft } \c_@@_FullLeft_chars_clist \xeCJK_declare_char_class:nV { FullRight } \c_@@_FullRight_chars_clist } % \end{macrocode} % \end{macro} % % % \begin{macro}{\xeCJKResetCharClass} % 用于恢复 \pkg{xeCJK} 对字符类别的设置。 % \begin{macrocode} \NewDocumentCommand \xeCJKResetCharClass { } { \xeCJK_declare_char_class:nV { CJK } \c_@@_CJK_chars_clist \xeCJK_declare_char_class:nV { NormalSpace } \c_@@_NormalSpace_chars_clist \xeCJK_declare_char_class:nV { IVS } \c_@@_IVS_chars_clist \xeCJKResetPunctClass } % \end{macrocode} % \end{macro} % % 设置字符类别。 % \begin{macrocode} \xeCJKResetCharClass % \end{macrocode} % % \begin{macro}[internal]{\xeCJK_inter_class_toks:nnn} % 在相邻类别之间插入内容。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_inter_class_toks:nnn #1#2#3 { \XeTeXinterchartoks \xeCJK_class_num:n {#1} ~ \xeCJK_class_num:n {#2} = {#3} } \cs_generate_variant:Nn \xeCJK_inter_class_toks:nnn { nnc , nnx } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_get_inter_class_toks:nn} % 取出相邻类别之间的内容。 % \begin{macrocode} \cs_new_nopar:Npn \xeCJK_get_inter_class_toks:nn #1#2 { \tex_the:D \XeTeXinterchartoks \xeCJK_class_num:n {#1} ~ \xeCJK_class_num:n {#2} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_clear_inter_class_toks:nn} % 清除相邻类别之间的内容。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_clear_inter_class_toks:nn #1#2 { \xeCJK_inter_class_toks:nnn {#1} {#2} { \prg_do_nothing: } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_pre_inter_class_toks:nnn} % 在相邻类别之间已有的内容前增加内容。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_pre_inter_class_toks:nnn #1#2#3 { \xeCJK_inter_class_toks:nnx {#1} {#2} { \exp_not:n {#3} \xeCJK_get_inter_class_toks:nn {#1} {#2} } } \cs_generate_variant:Nn \xeCJK_pre_inter_class_toks:nnn { nnx } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_app_inter_class_toks:nnn} % 在相邻类别之间已有的内容后追加内容。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_app_inter_class_toks:nnn #1#2#3 { \xeCJK_inter_class_toks:nnx {#1} {#2} { \xeCJK_get_inter_class_toks:nn {#1} {#2} \exp_not:n {#3} } } \cs_generate_variant:Nn \xeCJK_app_inter_class_toks:nnn { nnc , nnx } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_copy_inter_class_toks:nnnn} % 将 |#3| 和 |#4| 之间的内容复制到 |#1| 和 |#2| 之间。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_copy_inter_class_toks:nnnn #1#2#3#4 { \tl_set:Nx \l_@@_tmp_tl { \xeCJK_get_inter_class_toks:nn {#3} {#4} } \tl_if_empty:NF \l_@@_tmp_tl { \xeCJK_inter_class_toks:nnx {#1} {#2} { \exp_not:V \l_@@_tmp_tl } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_replace_inter_class_toks:nnnn} % 将 |#1| 和 |#2| 之间出现的 |#3| 用 |#4| 替换。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_replace_inter_class_toks:nnnn #1#2#3#4 { \tl_set:Nx \l_@@_tmp_tl { \xeCJK_get_inter_class_toks:nn {#1} {#2} } \tl_if_empty:NF \l_@@_tmp_tl { \tl_replace_all:Nnn \l_@@_tmp_tl {#3} {#4} \xeCJK_inter_class_toks:nnx {#1} {#2} { \exp_not:V \l_@@_tmp_tl } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_clear_Boundary_and_CJK_toks:} % 清除边界与 CJK 文字、全角左右标点之间的内容。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_clear_Boundary_and_CJK_toks: { \seq_map_function:NN \g_@@_CJK_class_seq \@@_clear_Boundary_and_CJK_toks:n } \cs_new_protected_nopar:Npn \@@_clear_Boundary_and_CJK_toks:n #1 { \xeCJK_clear_inter_class_toks:nn { Boundary } {#1} } % \end{macrocode} % \end{macro} % % \subsection{字符输出规则} % % \begin{center} % \begin{tabular}{l*9c} % \toprule % & |Default| & |CJK| & |FullL| & |FullR| & |HalfL| % & |HalfR| & |Normal| & |Bound| & |IVS| \\ \midrule % |Default| % & % & \tokslink{def-cjk} % & \tokslink{def-cjk} % & \tokslink{def-cjk} % & % & % & % & \tokslink{def-bound} % & \tokslink{def-IVS}\\ % |CJK| % & \tokslink{def-cjk} % & \tokslink{cjk-cjk} % & \tokslink{cjk-fl-fr} % & \tokslink{cjk-fl-fr} % & \tokslink{def-cjk} % & \tokslink{def-cjk} % & \tokslink{def-cjk} % & \tokslink{cjk-bound} % &\\ % |FullLeft| % & \tokslink{def-cjk} % & \tokslink{fl-fr-others} % & \tokslink{cjk-fl-fr} % & \tokslink{cjk-fl-fr} % & \tokslink{def-cjk} % & \tokslink{def-cjk} % & \tokslink{def-cjk} % & \tokslink{fl-fr-bound} % & \tokslink{def-IVS}\\ % |FullRight| % & \tokslink{def-cjk} % & \tokslink{fl-fr-others} % & \tokslink{cjk-fl-fr} % & \tokslink{cjk-fl-fr} % & \tokslink{def-cjk} % & \tokslink{def-cjk} % & \tokslink{def-cjk} % & \tokslink{fl-fr-bound} % & \tokslink{def-IVS}\\ % |HalfLeft| % & % & \tokslink{def-cjk} % & \tokslink{def-cjk} % & \tokslink{def-cjk} % & % & % & % & % & \tokslink{def-IVS}\\ % |HalfRight| % & % & \tokslink{def-cjk} % & \tokslink{def-cjk} % & \tokslink{def-cjk} % & % & % & % & \tokslink{def-bound} % & \tokslink{def-IVS}\\ % |NormalSpace| % & % & \tokslink{def-cjk} % & \tokslink{def-cjk} % & \tokslink{def-cjk} % & % & % & % & \tokslink{ns-bound} % & \tokslink{def-IVS}\\ % |Boundary| % & \tokslink{bound-def} % & \tokslink{bound-cjk} % & \tokslink{bound-fl-fr} % & \tokslink{bound-fl-fr} % & \tokslink{bound-def} % & % & \tokslink{bound-ns} % & % & \tokslink{def-IVS}\\ % |IVS| % & \tokslink{def-IVS} % & \tokslink{def-IVS} % & \tokslink{def-IVS} % & \tokslink{def-IVS} % & \tokslink{def-IVS} % & \tokslink{def-IVS} % & \tokslink{def-IVS} % & \tokslink{def-IVS} % & \tokslink{def-IVS}\\ % \bottomrule % \end{tabular} % \end{center} % % \begin{macro}[internal]{\xeCJK_class_group_begin:,\xeCJK_class_group_end:} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_class_group_begin: { \c_group_begin_token \bool_set_true:N \l_@@_CJK_group_bool } \bool_new:N \l_@@_CJK_group_bool \cs_new_eq:NN \xeCJK_class_group_end: \c_group_end_token % \end{macrocode} % \end{macro} % % \hypertarget{def-IVS}{\texttt{IVS}} 字符类与 |CJK| 字符类基本相同,只是从 |CJK| % 转移到 |IVS| 时,不加入任何内容。 % \begin{macrocode} \AtEndOfPackage { \seq_map_inline:Nn \g_@@_class_seq { \str_if_eq:nnTF {#1} { IVS } { \xeCJK_copy_inter_class_toks:nnnn { IVS } {#1} { CJK } { CJK } } { \xeCJK_copy_inter_class_toks:nnnn { IVS } {#1} { CJK } {#1} \str_if_eq:nnF {#1} { CJK } { \xeCJK_copy_inter_class_toks:nnnn {#1} { IVS } {#1} { CJK } } } } } % \end{macrocode} % % \hypertarget{def-cjk}{} % \begin{macrocode} \clist_map_inline:nn { Default , HalfLeft , HalfRight , NormalSpace } { \xeCJK_inter_class_toks:nnn {#1} { CJK } { \xeCJK_class_group_begin: \xeCJK_select_font: \xeCJK_clear_inter_class_toks:nn {#1} { CJK } \xeCJK_clear_Boundary_and_CJK_toks: \CJKsymbol } \xeCJK_inter_class_toks:nnn { CJK } {#1} { \xeCJK_class_group_end: } } % \end{macrocode} % % \hypertarget{bound-def}{} % \begin{macrocode} \clist_map_inline:nn { Default , HalfLeft } { \xeCJK_inter_class_toks:nnn { Boundary } {#1} { \xeCJK_Boundary_and_Default: } \xeCJK_app_inter_class_toks:nnn { CJK } {#1} { \CJKecglue } } % \end{macrocode} % % \begin{macro}[internal]{\xeCJK_Boundary_and_Default:} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_Boundary_and_Default: { \bool_if:nTF { \l_@@_xecglue_bool && \int_compare_p:nNn \etex_lastnodetype:D = \c_eleven && \skip_if_eq_p:nn \tex_lastskip:D \c_xeCJK_space_skip_tl } { \tex_unskip:D \bool_if:nTF { \xeCJK_if_last_node_p:n { CJK } || \xeCJK_if_last_node_p:n { CJK-space } } { \xeCJK_remove_node: \CJKecglue } { ~ } } { \bool_if:nTF { \xeCJK_if_last_node_p:n { CJK } || \xeCJK_if_last_node_p:n { CJK-nobreak } } { \xeCJK_remove_node: \CJKecglue } { \xeCJK_if_last_node:nT { CJK-space } { \xeCJK_remove_node: \xeCJK_space_or_xecglue: } } } } % \end{macrocode} % \end{macro} % % \hypertarget{def-bound}{} % \begin{macrocode} \clist_map_inline:nn { Default , HalfRight } { \xeCJK_inter_class_toks:nnn {#1} { Boundary } { \int_gset_eq:NN \g_@@_spacefactor_int \tex_spacefactor:D \peek_meaning_remove:NTF \tex_italiccorrection:D { \tex_italiccorrection:D { \xeCJK_make_node:n { default } } } { \token_if_space:NTF \l_peek_token { { \xeCJK_make_node:n { default-space } } } { { \xeCJK_make_node:n { default } } } } } \xeCJK_pre_inter_class_toks:nnn {#1} { CJK } { \CJKecglue } } % \end{macrocode} % % \changes{v3.2.5}{2013/07/10} % {修正 \texttt{CJK} 和 \texttt{NormalSpace} 字符类之间因为边界造成的间距不正确的问题。} % % \hypertarget{bound-ns}{} % \begin{macrocode} \xeCJK_inter_class_toks:nnn { Boundary } { NormalSpace } { \xeCJK_Boundary_and_NormalSp: } % \end{macrocode} % % \begin{macro}[internal]{\xeCJK_Boundary_and_NormalSp:} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_Boundary_and_NormalSp: { \bool_if:nTF { \l_@@_xecglue_bool && \int_compare_p:nNn \etex_lastnodetype:D = \c_eleven && \skip_if_eq_p:nn \tex_lastskip:D \c_xeCJK_space_skip_tl } { \tex_unskip:D \bool_if:nTF { \xeCJK_if_last_node_p:n { CJK } || \xeCJK_if_last_node_p:n { CJK-space } } { \xeCJK_remove_node: \CJKecglue } { ~ } } { \xeCJK_if_last_node:nT { CJK-space } { \xeCJK_remove_node: \xeCJK_space_or_xecglue: } } } % \end{macrocode} % \end{macro} % % \hypertarget{ns-bound}{} % \begin{macrocode} \xeCJK_inter_class_toks:nnn { NormalSpace } { Boundary } { \int_gset_eq:NN \g_@@_spacefactor_int \tex_spacefactor:D \peek_meaning_remove:NTF \tex_italiccorrection:D { \tex_italiccorrection:D { \xeCJK_make_node:n { normalspace } } } { \token_if_space:NTF \l_peek_token { { \xeCJK_make_node:n { default-space } } } { { \xeCJK_make_node:n { normalspace } } } } } % \end{macrocode} % % \hypertarget{bound-cjk}{} % \begin{macrocode} \xeCJK_inter_class_toks:nnn { Boundary } { CJK } { \xeCJK_check_for_glue: \xeCJK_class_group_begin: \xeCJK_clear_Boundary_and_CJK_toks: \xeCJK_select_font: \CJKsymbol } % \end{macrocode} % % \begin{macro}[internal]{\xeCJK_check_for_glue:} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_check_for_glue: { \bool_if:nTF { \xeCJK_if_last_node_p:n { CJK } || \xeCJK_if_last_node_p:n { CJK-space } } { \xeCJK_remove_node: \CJKglue } { \xeCJK_if_last_node:nTF { CJK-nobreak } { \xeCJK_remove_node: \xeCJK_no_break: \CJKglue } { \bool_if:nTF { \xeCJK_if_last_node_p:n { default } || \int_compare_p:nNn \etex_lastnodetype:D = \c_ten } { \xeCJK_remove_node: \CJKecglue } { \bool_if:nT { \l_@@_xecglue_bool && \int_compare_p:nNn \etex_lastnodetype:D = \c_eleven && ( \skip_if_eq_p:nn \tex_lastskip:D \c_xeCJK_space_skip_tl || \skip_if_eq_p:nn \tex_lastskip:D \l_@@_ecglue_skip ) } { \tex_unskip:D \bool_if:nTF { \xeCJK_if_last_node_p:n { default-space } || \int_compare_p:nNn \etex_lastnodetype:D = \c_ten || \xeCJK_if_last_node_p:n { default } } { \xeCJK_remove_node: \CJKecglue } { \bool_if:nTF { \xeCJK_if_last_node_p:n { CJK } || \xeCJK_if_last_node_p:n { CJK-space } } { \xeCJK_remove_node: \bool_if:NTF \l_@@_reserve_space_bool { ~ } { \CJKglue } } { ~ } } } } } } } % \end{macrocode} % \end{macro} % % \begin{macro}[pTF,internal]{\xeCJK_if_last_node:n} % \begin{macrocode} \prg_new_conditional:Npnn \xeCJK_if_last_node:n #1 { p , T , F , TF } { \if_dim:w \use:c { c_@@_#1_node_dim } = \tex_lastkern:D \prg_return_true: \else: \prg_return_false: \fi: } % \end{macrocode} % \end{macro} % % \changes{v3.1.0}{2012/11/14}{删除多余的 \texttt{default-itcorr} 结点。} % \changes{v3.2.4}{2013/07/03}{尽量移除用作判断标志的 \cs{kern}。} % % \begin{macro}[internal]{\xeCJK_def_node:nn,\xeCJK_make_node:n} % 用于判断插入的各种 |kern|。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_def_node:nn #1#2 { \dim_if_exist:cTF { c_@@_#1_node_dim } { \dim_gset:cn } { \dim_const:cn } { c_@@_#1_node_dim } {#2} } \cs_new_protected_nopar:Npn \xeCJK_make_node:n #1 { \tex_kern:D - \use:c { c_@@_#1_node_dim } \tex_kern:D \use:c { c_@@_#1_node_dim } } \cs_new_protected_nopar:Npn \xeCJK_remove_node: { \tex_unkern:D \tex_unkern:D } \xeCJK_def_node:nn { CJK } { 11 sp } \xeCJK_def_node:nn { CJK-space } { 12 sp } \xeCJK_def_node:nn { default } { 13 sp } \xeCJK_def_node:nn { default-space } { 14 sp } \xeCJK_def_node:nn { CJK-nobreak } { 15 sp } \xeCJK_def_node:nn { normalspace } { 16 sp } % \end{macrocode} % \end{macro} % % \begin{macro}{CJKglue} % CJK 文字之间插入的 |glue|。 % \begin{macrocode} \keys_define:nn { xeCJK / options } { CJKglue .code:n = { \cs_set_protected_nopar:Npn \CJKglue {#1} \xeCJK_glue_to_skip:nN {#1} \l_@@_ccglue_skip } } \skip_new:N \l_@@_ccglue_skip % \end{macrocode} % \end{macro} % % \begin{macro}{CJKecglue,xCJKecglue} % CJK 与西文和数学行内数学公式之间自动添加的空白。 % \begin{macrocode} \keys_define:nn { xeCJK / options } { CJKecglue .code:n = { \cs_set_protected_nopar:Npn \CJKecglue {#1} \xeCJK_glue_to_skip:nN {#1} \l_@@_ecglue_skip } , xCJKecglue .choice: , xCJKecglue / true .code:n = { \bool_set_true:N \l_@@_xecglue_bool \cs_set_eq:NN \xeCJK_space_or_xecglue: \CJKecglue } , xCJKecglue / false .code:n = { \bool_set_false:N \l_@@_xecglue_bool \cs_set_eq:NN \xeCJK_space_or_xecglue: \c_space_tl } , xCJKecglue / unknown .code:n = { \bool_set_true:N \l_@@_xecglue_bool \cs_set_protected_nopar:Npn \CJKecglue {#1} \xeCJK_glue_to_skip:nN {#1} \l_@@_ecglue_skip \cs_set_eq:NN \xeCJK_space_or_xecglue: \CJKecglue } , xCJKecglue .default:n = { true } } \skip_new:N \l_@@_ecglue_skip \bool_new:N \l_@@_xecglue_bool % \end{macrocode} % \end{macro} % % \begin{macro}{CJKspace} % 是否保留 CJK 文字间的空白,默认不保留。 % \begin{macrocode} \keys_define:nn { xeCJK / options } { CJKspace .bool_set:N = \l_@@_reserve_space_bool , space .meta:n = { CJKspace = true } , nospace .meta:n = { CJKspace = false } } % \end{macrocode} % \end{macro} % % \hypertarget{cjk-bound}{} % \begin{macrocode} \xeCJK_inter_class_toks:nnn { CJK } { Boundary } { \xeCJK_class_group_end: { \xeCJK_make_node:n { CJK } } \xeCJK_ignore_spaces:w } % \end{macrocode} % % \begin{macro}[internal]{\xeCJK_ignore_spaces:w} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_ignore_spaces:w { \xeCJK_peek_catcode_ignore_spaces:NTF \c_math_toggle_token { \bool_if:NTF \l_@@_peek_ignore_spaces_bool { \xeCJK_space_or_xecglue: } { \CJKecglue } } { \bool_if:NTF \l_@@_peek_ignore_spaces_bool { \xeCJK_remove_node: { \xeCJK_make_node:n { CJK-space } } \bool_if:nT { \token_if_macro_p:N \l_peek_token || ( \l_@@_reserve_space_bool && \token_if_letter_p:N \l_peek_token ) } { \xeCJK_space_or_xecglue: } } { \@@_CJK_and_Boundary_aux: } } } \cs_new_protected_nopar:Npn \@@_CJK_and_Boundary_aux: { \cs_if_exist:NF \l_peek_token \exp_not:N } % \end{macrocode} % \end{macro} % % \hypertarget{cjk-cjk}{} % \begin{macrocode} \xeCJK_inter_class_toks:nnn { CJK } { CJK } { \xeCJK_CJK_and_CJK:N } % \end{macrocode} % % \begin{macro}[internal]{\xeCJK_CJK_and_CJK:N} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_CJK_and_CJK:N #1 { \CJKglue \CJKsymbol {#1} } % \end{macrocode} % \end{macro} % % \hypertarget{fl-fr-others}{} % \begin{macrocode} \xeCJK_inter_class_toks:nnn { FullLeft } { CJK } { \xeCJK_FullLeft_and_CJK: \CJKsymbol } \xeCJK_inter_class_toks:nnn { FullRight } { CJK } { \xeCJK_FullRight_and_CJK: \CJKsymbol } \seq_map_inline:Nn \g_@@_non_CJK_class_seq { \clist_map_inline:nn { FullLeft , FullRight } { \xeCJK_inter_class_toks:nnx {#1} {##1} { \exp_not:c { xeCJK_Default_and_##1:nN } {#1} } \xeCJK_inter_class_toks:nnc {##1} {#1} { xeCJK_##1_and_Default: } } } % \end{macrocode} % % \hypertarget{bound-fl-fr}{} % \begin{macrocode} \xeCJK_inter_class_toks:nnn { Boundary } { FullLeft } { \xeCJK_Boundary_and_FullLeft:N } \xeCJK_inter_class_toks:nnn { Boundary } { FullRight } { \xeCJK_Boundary_and_FullRight:N } % \end{macrocode} % % \begin{macro}[internal]{\xeCJK_FullRight_and_Boundary:} % \hypertarget{fl-fr-bound}{} % \begin{macrocode} \xeCJK_app_inter_class_toks:nnn { FullLeft } { Boundary } { \tex_ignorespaces:D } \xeCJK_inter_class_toks:nnn { FullRight } { Boundary } { \xeCJK_FullRight_and_Boundary: } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_FullRight_and_Boundary:} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_FullRight_and_Boundary: { \xeCJK_FullRight_and_Default: \tex_ignorespaces:D } % \end{macrocode} % \end{macro} % % \hypertarget{cjk-fl-fr}{} % \begin{macrocode} \clist_map_inline:nn { CJK , FullLeft , FullRight } { \clist_map_inline:nn { FullLeft , FullRight } { \xeCJK_inter_class_toks:nnc {#1} {##1} { xeCJK_#1_and_##1:N } } } % \end{macrocode} % % \begin{macro}[internal]{\@@_punct_rule:NN} % 用于抹去标点符号的左/右空白。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_punct_rule:NN #1#2 { \tex_vrule:D width - \@@_use_punct_dim:nnn { bound } {#1} {#2} depth \c_zero_dim height \c_zero_dim \scan_stop: } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_punct_glue:NN} % 根据所选的标点处理方式在标点符号左/右增加的空白。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_punct_glue:NN #1#2 { \@@_punct_hskip:n { \@@_use_punct_dim:nnn { glue } {#1} {#2} minus \dim_eval:n { ( \@@_use_punct_dim:nnn { glue } {#1} {#2} ) / \c_two } } } \cs_new_eq:NN \@@_punct_hskip:n \skip_horizontal:n % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_punct_kern:NN} % 相邻两个标点之间的间距。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_punct_kern:NN #1#2 { \tex_kern:D \@@_use_punct_dim:nnn { kern } {#1} {#2} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal,var]{\g_@@_last_punct_tl} % 用于记录当前的标点符号。 % \begin{macrocode} \tl_new:N \g_@@_last_punct_tl % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_FullLeft_and_CJK:} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_FullLeft_and_CJK: { \@@_punct_if_middle:NTF \g_@@_last_punct_tl { \@@_punct_rule:NN \c_@@_right_tl \g_@@_last_punct_tl \xeCJK_no_break: \@@_punct_glue:NN \c_@@_left_tl \g_@@_last_punct_tl } { \xeCJK_no_break: } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_FullLeft_and_Default:} % \changes{v3.2.0}{2013/05/20}{修正 \pkg{xeCJK} 使西文在部分情况下无法断词的问题。} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_FullLeft_and_Default: { \@@_punct_if_middle:NTF \g_@@_last_punct_tl { \@@_punct_rule:NN \c_@@_right_tl \g_@@_last_punct_tl \xeCJK_class_group_end: \xeCJK_no_break: \@@_punct_glue:NN \c_@@_left_tl \g_@@_last_punct_tl } { \xeCJK_class_group_end: \xeCJK_no_break: \@@_zero_glue: } } \cs_new_protected_nopar:Npn \@@_zero_glue: { \skip_horizontal:N \c_zero_skip } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_FullRight_and_CJK:} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_FullRight_and_CJK: { \@@_punct_rule:NN \c_@@_right_tl \g_@@_last_punct_tl \@@_punct_glue:NN \c_@@_right_tl \g_@@_last_punct_tl \CJKglue } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_FullRight_and_Default:} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_FullRight_and_Default: { \@@_punct_rule:NN \c_@@_right_tl \g_@@_last_punct_tl \xeCJK_class_group_end: \@@_punct_glue:NN \c_@@_right_tl \g_@@_last_punct_tl } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_Default_and_FullLeft:nN} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_Default_and_FullLeft:nN #1#2 { \xeCJK_get_punct_bounds:NN \c_@@_left_tl {#2} \@@_Default_and_FullLeft_glue:N {#2} \xeCJK_class_group_begin: \xeCJK_select_font: \xeCJK_clear_inter_class_toks:nn {#1} { FullLeft } \xeCJK_clear_Boundary_and_CJK_toks: \tl_gset:Nx \g_@@_last_punct_tl {#2} \@@_punct_rule:NN \c_@@_left_tl {#2} \CJKpunctsymbol {#2} } \cs_new_protected_nopar:Npn \@@_Default_and_FullLeft_glue:N #1 { \@@_punct_glue:NN \c_@@_left_tl {#1} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_CJK_and_FullLeft:N} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_CJK_and_FullLeft:N #1 { \xeCJK_get_punct_bounds:NN \c_@@_left_tl {#1} \@@_CJK_and_FullLeft_glue:N {#1} \tl_gset:Nx \g_@@_last_punct_tl {#1} \@@_punct_rule:NN \c_@@_left_tl {#1} \CJKpunctsymbol {#1} } \cs_new_protected_nopar:Npn \@@_CJK_and_FullLeft_glue:N #1 { \CJKglue \@@_punct_glue:NN \c_@@_left_tl {#1} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_Boundary_and_FullLeft:N} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_Boundary_and_FullLeft:N #1 { \xeCJK_get_punct_bounds:NN \c_@@_left_tl {#1} \@@_Boundary_and_FullLeft_glue:N {#1} \xeCJK_class_group_begin: \xeCJK_select_font: \xeCJK_clear_Boundary_and_CJK_toks: \tl_gset:Nx \g_@@_last_punct_tl {#1} \@@_punct_rule:NN \c_@@_left_tl {#1} \CJKpunctsymbol {#1} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_Boundary_and_FullLeft_glue:N} % \changes{v3.2.0}{2013/05/22}{当全角左标点前面是 \texttt{hlist}、\texttt{none}、 % \texttt{glue} 和 \texttt{penalty} 等节点时,压缩其左空白。} % \changes{v3.2.4}{2013/07/03}{细化边界与全角左标点之间是否压缩空白的判断。} % \changes{v3.2.5}{2013/07/13}{细化全角左标点是否位于段首的判断。} % \changes{v3.2.5}{2013/07/13}{增加对 \pkg{enumitem} 宏包修改的 \cs{item} 的判断。} % \cs{etex_lastnodetype:D} 为 $1$ 表示 hlist node,在这里用来判断是否位于段首。基于 % 正常情况下,\TeX 会在段落开头插入宽度为 \cs{parindent} 的水平盒子用于缩进。 % $-1$ 表示 empty list,常出现在盒子的起始位置,在段落前使用 \cs{noindent} 就 % 是这种情况。$11$ 表示 glue node,这里判断的目的是当全角左标点出现在 \LaTeX 表格 % 的非 \texttt{p} 列行首时,能够对齐到单元格的边界。判断基于标准 \LaTeX 表格的 % 列格式(\cs{@tabclassz})定义中,在 \texttt{l} 列和 \texttt{r} 列前为了防止 % \cs{tabcolsep} 被无意 \cs{unskip} 掉,都加了 |\hskip1sp|,而 \texttt{c} 列前 % 则有 \cs{hfil}。$13$ 表示 penalty node,这里判断的目的是全角左标点出现在 \LaTeX % 列表环境的 \cs{item} 后面时,能对齐到边界。判断基于 \cs{item} 的内部定义 % \cs{@item} 对 \cs{everypar} 进行了修改,在这里起到影响作用的是 % |\box\@labels \penalty\z@|。\package{enumitem} 宏包修改了 \env{description} % 环境中使用的 \cs{item}(\cs{enit@postlabel@i}),在这里起到影响作用的是 % |\penalty\z@ \hskip\labelsep|。以上判断都比较粗略,暂时也没有想起更好的办法。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_Boundary_and_FullLeft_glue:N #1 { \int_case:nnn { \etex_lastnodetype:D } { { \c_one } { \box_set_to_last:N \l_@@_tmp_box \bool_if:nTF { \int_compare_p:nNn \etex_lastnodetype:D = \c_minus_one && \dim_compare_p:nNn { \box_wd:N \l_@@_tmp_box } = \tex_parindent:D } { \box_use_clear:N \l_@@_tmp_box \use_none:n } { \box_use_clear:N \l_@@_tmp_box \use:n } } { \c_minus_one } { \use_none:n } { \c_eleven } { \bool_if:nTF { ! ( \skip_if_finite_p:n { \tex_lastskip:D } ) || \skip_if_eq_p:nn { \tex_lastskip:D } { 1 sp } } { \use_none:n } { \skip_if_eq:nnTF { \tex_lastskip:D } { \labelsep } { \tex_unskip:D \bool_if:nTF { \int_compare_p:nNn \etex_lastnodetype:D = \c_thirteen && \int_compare_p:nNn \tex_lastpenalty:D = \c_zero } { \skip_horizontal:n { \labelsep } \use_none:n } { \skip_horizontal:n { \labelsep } \use:n } } { \use:n } } } { \c_thirteen } { \int_compare:nNnTF \tex_lastpenalty:D = \c_zero { \tex_unpenalty:D \int_compare:nNnTF \etex_lastnodetype:D = \c_one { \tex_penalty:D \c_zero \use_none:n } { \tex_penalty:D \c_zero \use:n } } { \use:n } } } { \use:n } { \@@_punct_glue:NN \c_@@_left_tl {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_Default_and_FullRight:nN} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_Default_and_FullRight:nN #1#2 { \xeCJK_get_punct_bounds:NN \c_@@_right_tl {#2} \@@_Default_and_FullRight_glue:N {#2} \xeCJK_class_group_begin: \xeCJK_select_font: \xeCJK_clear_inter_class_toks:nn {#1} { FullRight } \xeCJK_clear_Boundary_and_CJK_toks: \tl_gset:Nx \g_@@_last_punct_tl {#2} \@@_punct_if_middle:NT {#2} { \@@_punct_rule:NN \c_@@_left_tl {#2} } \xeCJK_FullRight_symbol:N {#2} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_Boundary_and_FullRight:N} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_Boundary_and_FullRight:N #1 { \xeCJK_get_punct_bounds:NN \c_@@_right_tl {#1} \@@_Default_and_FullRight_glue:N {#1} \xeCJK_class_group_begin: \xeCJK_select_font: \xeCJK_clear_Boundary_and_CJK_toks: \tl_gset:Nx \g_@@_last_punct_tl {#1} \@@_punct_if_middle:NT {#1} { \@@_punct_rule:NN \c_@@_left_tl {#1} } \xeCJK_FullRight_symbol:N {#1} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_CJK_and_FullRight:N} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_CJK_and_FullRight:N #1 { \xeCJK_get_punct_bounds:NN \c_@@_right_tl {#1} \@@_CJK_and_FullRight_glue:N {#1} \tl_gset:Nx \g_@@_last_punct_tl {#1} \@@_punct_if_middle:NT {#1} { \@@_punct_rule:NN \c_@@_left_tl {#1} } \xeCJK_FullRight_symbol:N {#1} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal] % {\@@_CJK_and_FullRight_glue:N,\@@_Default_and_FullRight_glue:N} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_CJK_and_FullRight_glue:N #1 { \@@_punct_if_long:NTF {#1} { \CJKglue } { \xeCJK_no_break: \@@_punct_if_middle:NT {#1} { \@@_punct_glue:NN \c_@@_right_tl {#1} } } } \cs_new_eq:NN \@@_Default_and_FullRight_glue:N \@@_CJK_and_FullRight_glue:N % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_FullLeft_and_FullLeft:N} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_FullLeft_and_FullLeft:N #1 { \xeCJK_no_break: \xeCJK_get_punct_bounds:NN \c_@@_left_tl {#1} \xeCJK_get_punct_kerning:oN \g_@@_last_punct_tl {#1} \@@_punct_kern:NN \g_@@_last_punct_tl {#1} \tl_gset:Nx \g_@@_last_punct_tl {#1} \CJKpunctsymbol {#1} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_FullLeft_and_FullRight:N} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_FullLeft_and_FullRight:N #1 { \xeCJK_no_break: \xeCJK_get_punct_bounds:NN \c_@@_right_tl {#1} \xeCJK_get_punct_kerning:oN \g_@@_last_punct_tl {#1} \@@_punct_kern:NN \g_@@_last_punct_tl {#1} \tl_gset:Nx \g_@@_last_punct_tl {#1} \xeCJK_no_break: \xeCJK_FullRight_symbol:N {#1} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_FullRight_and_FullLeft:N} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_FullRight_and_FullLeft:N #1 { \xeCJK_get_punct_bounds:NN \c_@@_left_tl {#1} \xeCJK_get_punct_kerning:oN \g_@@_last_punct_tl {#1} \xeCJK_punct_kern:NN \g_@@_last_punct_tl {#1} \tl_gset:Nx \g_@@_last_punct_tl {#1} \CJKpunctsymbol {#1} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_punct_nobreak_kern:NN} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_punct_nobreak_kern:NN #1#2 { \@@_punct_kern:NN #1#2 \xeCJK_no_break: } \cs_new_eq:NN \xeCJK_punct_kern:NN \@@_punct_nobreak_kern:NN % \end{macrocode} % \end{macro} % % \changes{v3.2.4}{2013/07/06} % {使用 \texttt{AllowBreakBetweenPuncts} 时,相应标点符号仍能与边界对齐。} % % \begin{macro}[internal]{\@@_punct_breakable_kern:NN} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_punct_breakable_kern:NN #1#2 { \@@_punct_rule:NN \c_@@_right_tl #1 \@@_punct_hskip:n { \@@_use_punct_dim:nnn { kern } {#1} {#2} + \@@_use_punct_dim:nnn { bound } { \c_@@_right_tl } {#1} + \@@_use_punct_dim:nnn { bound } { \c_@@_left_tl } {#2} } \@@_punct_rule:NN \c_@@_left_tl #2 } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_FullRight_and_FullRight:N} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_FullRight_and_FullRight:N #1 { \xeCJK_get_punct_bounds:NN \c_@@_right_tl {#1} \xeCJK_get_punct_kerning:oN \g_@@_last_punct_tl {#1} \@@_punct_kern:NN \g_@@_last_punct_tl {#1} \tl_gset:Nx \g_@@_last_punct_tl {#1} \xeCJK_no_break: \xeCJK_FullRight_symbol:N {#1} } % \end{macrocode} % \end{macro} % % \subsection{全角右标点后的断行} % % \begin{macro}{CheckFullRight} % \changes{v3.1.1}{2012/12/02}{处理全角右标点之后的断行问题。} % 选项设置。 % \begin{macrocode} \keys_define:nn { xeCJK / options } { CheckFullRight .choice: , CheckFullRight / true .code:n = { \cs_if_eq:NNF \xeCJK_FullRight_and_Boundary: \xeCJK_check_FullRight: { \cs_set_eq:NN \@@_save_FullRight_check: \xeCJK_FullRight_and_Boundary: \cs_set_eq:NN \@@_save_FullRight_symbol:N \xeCJK_FullRight_symbol:N \cs_set_eq:NN \xeCJK_FullRight_and_Boundary: \xeCJK_check_FullRight: \cs_set_eq:NN \xeCJK_FullRight_symbol:N \xeCJK_check_FullRight_symbol:Nw } } , CheckFullRight / false .code:n = { \cs_if_eq:NNT \xeCJK_FullRight_and_Boundary: \xeCJK_check_FullRight: { \cs_set_eq:NN \xeCJK_FullRight_and_Boundary: \@@_save_FullRight_check: \cs_set_eq:NN \xeCJK_FullRight_symbol:N \@@_save_FullRight_symbol:N } } , CheckFullRight .default:n = { true } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_FullRight_symbol:N} % \begin{macrocode} \cs_new_nopar:Npn \xeCJK_FullRight_symbol:N { \CJKpunctsymbol } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_check_FullRight:} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_check_FullRight: { \xeCJK_get_punct_bounds:NN \c_@@_right_tl \g_@@_last_punct_tl \@@_punct_rule:NN \c_@@_right_tl \g_@@_last_punct_tl \tl_case:Non \l_peek_token { \l_@@_no_break_cs_case_tl } { } \@@_punct_glue:NN \c_@@_right_tl \g_@@_last_punct_tl \xeCJK_class_group_end: } \cs_generate_variant:Nn \tl_case:Nnn { No } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_check_FullRight_symbol:Nw} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_check_FullRight_symbol:Nw #1 { \xeCJK_peek_after_ignore_spaces:nw { \@@_save_FullRight_symbol:N {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_cs_case_keys_define:nNNnn} % \begin{macrocode} \cs_new_protected:Npn \xeCJK_cs_case_keys_define:nNNnn #1#2#3#4#5 { \tl_new:N #2 \seq_new:N #3 \keys_define:nn { xeCJK / options } { #1 .code:n = { \seq_set_split:Nnn #3 { } {##1} \@@_update_cs_case_tl:NNnn #2#3 {#4} {#5} } , #1+ .code:n = { \tl_map_inline:nn {##1} { \seq_if_in:NnF #3 {####1} { \seq_put_right:Nn #3 {####1} } } \@@_update_cs_case_tl:NNnn #2#3 {#4} {#5} } , #1- .code:n = { \tl_map_inline:nn {##1} { \seq_remove_all:Nn #3 {####1} } \@@_update_cs_case_tl:NNnn #2#3 {#4} {#5} } } } \cs_new_protected:Npn \@@_update_cs_case_tl:NNnn #1#2#3#4 { \tl_clear:N #1 \seq_map_inline:Nn #2 { \tl_put_right:Nn #1 { {##1} {#3} } } #4 } % \end{macrocode} % \end{macro} % % \begin{macro}{NoBreakCS} % 设置不能在全角右标点之后断行的控制序列。 % \begin{macrocode} \xeCJK_cs_case_keys_define:nNNnn { NoBreakCS } \l_@@_no_break_cs_case_tl \l_@@_no_break_cs_seq { \xeCJK_no_break: } { } % \end{macrocode} % \end{macro} % % \begin{macro}{\xeCJKnobreak} % \changes{v3.1.1}{2012/12/03}{增加 \cs{nobreak} 的 \pkg{xeCJK} 版本。} % 为保险起见,我们在这里用了一个循环。 % \begin{macrocode} \NewDocumentCommand \xeCJKnobreak { } { \bool_set_true:N \l_@@_tmp_bool \int_while_do:nNnn \etex_lastnodetype:D = \c_eleven { \bool_if:NTF \l_@@_tmp_bool { \bool_set_false:N \l_@@_tmp_bool \skip_set_eq:NN \l_@@_tmp_skip \tex_lastskip:D } { \skip_add:Nn \l_@@_tmp_skip \tex_lastskip:D } \tex_unskip:D } \xeCJK_no_break: \bool_if:NF \l_@@_tmp_bool { \skip_horizontal:N \l_@@_tmp_skip } } % \end{macrocode} % \end{macro} % % \subsection{段末孤字处理} % % \begin{macro}{CheckSingle} % 孤字处理功能选项。 % \begin{macrocode} \keys_define:nn { xeCJK / options } { CheckSingle .choice: , CheckSingle / true .code:n = { \cs_if_eq:NNF \xeCJK_CJK_and_CJK:N \xeCJK_check_single:Nw { \cs_set_eq:NN \@@_check_single_save:N \xeCJK_CJK_and_CJK:N \cs_set_eq:NN \xeCJK_CJK_and_CJK:N \xeCJK_check_single:Nw } } , CheckSingle / false .code:n = { \cs_if_eq:NNT \xeCJK_CJK_and_CJK:N \xeCJK_check_single:Nw { \cs_set_eq:NN \xeCJK_CJK_and_CJK:N \@@_check_single_save:N } } , CheckSingle .default:n = { true } , CJKchecksingle .meta:n = { CheckSingle = true } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_check_single:Nw} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_check_single:Nw #1 { \peek_catcode:NTF \c_catcode_letter_token { \xeCJK_check_single:NNw #1 } { \token_if_other:NTF \l_peek_token { \xeCJK_check_single:NNw #1 } { \bool_if:nTF { \xeCJK_if_blank_x_p:n { \token_get_arg_spec:N \l_peek_token } && \exp_args:No \tl_if_single_token_p:n \l_peek_token && ( \exp_after:wN \token_if_other_p:N \l_peek_token || \exp_after:wN \token_if_letter_p:N \l_peek_token ) } { \exp_after:wN \xeCJK_check_single:NNw \exp_after:wN #1 } { \@@_check_single_save:N #1 } } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_check_single:NNw} % \changes{v3.1.1}{2012/12/04}{改进定义,减少使用 \texttt{peek} 函数的次数。} % 使用 \cs{group_align_safe_begin:} 和 \cs{group_align_safe_end:} 是为了防止在表格 % 里面报错。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_check_single:NNw #1#2 { \xeCJK_peek_catcode_ignore_spaces:NTF \c_catcode_letter_token { \bool_if:NTF \l_@@_peek_ignore_spaces_bool { \@@_check_single_space:NN #1#2 } { \@@_check_single_save:N #1 #2 } } { \group_align_safe_begin: \token_if_other:NTF \l_peek_token { \group_align_safe_end: \bool_if:NTF \l_@@_peek_ignore_spaces_bool { \@@_check_single_space:NN #1#2 } { \@@_check_single_save:N #1 #2 } } { \token_if_cs:NTF \l_peek_token { \group_align_safe_end: \bool_if:NTF \l_@@_peek_ignore_spaces_bool { \xeCJK_check_single_cs:NNn #1#2 { ~ } } { \xeCJK_check_single_cs:NNn #1#2 { } } } { \group_align_safe_end: \bool_if:nTF { \l_@@_plain_equation_bool && \token_if_math_toggle_p:N \l_peek_token } { \bool_if:NTF \l_@@_peek_ignore_spaces_bool { \xeCJK_check_single_equation:NNnNw #1 #2 { ~ } } { \xeCJK_check_single_equation:NNnNw #1 #2 { } } } { \bool_if:NTF \l_@@_peek_ignore_spaces_bool { \@@_check_single_save:N #1 #2 ~ } { \@@_check_single_save:N #1 #2 } } } } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_check_single_space:NN} % \changes{v3.1.1}{2012/12/13} % {\texttt{CheckSingle} 支持段末“汉字$+$汉字$+$空格$+$汉字/标点”的形式。} % \changes{v3.1.2}{2012/12/27} % {使用 \cs{xeCJK_if_CJK_class:NTF} 来代替 \cs{int_case:nnn} 判断是否是 CJK 字符类。} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_check_single_space:NN #1#2 { \xeCJK_if_CJK_class:NTF #2 { \xeCJK_if_CJK_class:NTF \l_peek_token { \@@_check_single_save:N #1 #2 } { \@@_check_single_save:N #1 #2 ~ } } { \@@_check_single_save:N #1 #2 ~ } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_check_single_equation:NNnNw} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_check_single_equation:NNnNw #1#2#3#4 { \peek_catcode:NTF \c_math_toggle_token { \xeCJK_no_break: \@@_check_single_save:N #1 \xeCJK_make_node:n { CJK-nobreak } #2 #4 } { \@@_check_single_save:N #1 #2#3#4 } } % \end{macrocode} % \end{macro} % % \changes{v3.2.3}{2013/06/11} % {解决 \texttt{CheckSingle} 选项与 \pkg{tablists} 宏包的冲突。} % \changes{v3.2.4}{2013/06/26} % {解决使用 \texttt{CheckSingle} 时,某些 \cs{CJKglue} 不能被正确加入的问题。} % % \begin{macro}[internal]{\xeCJK_check_single_cs:NNn} % 在使用 \texttt{CheckSingle} 选项时,在 \package{tablists} 宏包定义的 % \env{tabenum} 环境中会出现下面的错误: % \begin{verbatim} % ! Forbidden control sequence found while scanning use of \use_ii:nn. % % \par % l.10 \item % \end{verbatim} % 原因在于 \env{tabenum} 实际上是一个 \TeX 对齐环境(\cs{halign}),\cs{par} 在 % 其中被重定义为 \cs{cr}。而在下面 \cs{tl_case:Nnn} 的分支里有对 \cs{par} 的 % \cs{ifx} 判断。解决办法是将判断用 \cs{group_align_safe_begin:} 和 % \cs{group_align_safe_end:} 包起来。或者改用原语 \cs{tex_par:D} 作为判断条件。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_check_single_cs:NNn #1#2#3 { \group_align_safe_begin: \tl_case:Non \l_peek_token { \l_@@_check_single_cs_case_tl } { \group_align_safe_end: \use_iii:nnn } { \xeCJK_check_single_env:nnNn } { \xeCJK_no_break: \@@_check_single_save:N #1 \xeCJK_make_node:n { CJK-nobreak } #2 } { \@@_check_single_save:N #1 #2#3 } } \tl_new:N \l_@@_check_single_cs_case_tl % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_check_single_env:nnNn} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_check_single_env:nnNn #1#2#3#4 { \group_align_safe_begin: \str_case_x:non {#4} { \l_@@_inline_env_case_tl } { \group_align_safe_end: \use_i:nn } {#1} {#2} \scan_stop: #3 {#4} } \cs_generate_variant:Nn \str_case_x:nnn { no } % \end{macrocode} % \end{macro} % % \changes{v3.1.1}{2012/12/04}{增加 \texttt{NewLineCS} 和 \texttt{EnvCS} 选项。} % % \begin{macro}{NewLineCS} % \begin{macrocode} \xeCJK_cs_case_keys_define:nNNnn { NewLineCS } \l_@@_new_line_cs_case_tl \l_@@_new_line_cs_seq { \group_align_safe_end: \use_ii:nnn } { \tl_concat:NNN \l_@@_check_single_cs_case_tl \l_@@_new_line_cs_case_tl \l_@@_env_cs_case_tl } % \end{macrocode} % \end{macro} % % \begin{macro}{EnvCS} % \begin{macrocode} \xeCJK_cs_case_keys_define:nNNnn { EnvCS } \l_@@_env_cs_case_tl \l_@@_env_cs_seq { \group_align_safe_end: \use:n } { \tl_concat:NNN \l_@@_check_single_cs_case_tl \l_@@_new_line_cs_case_tl \l_@@_env_cs_case_tl } % \end{macrocode} % \end{macro} % % \begin{macro}{InlineEnv} % \changes{v3.1.1}{2012/12/05}{改变行内环境的设置方式,从而使用 \cs{str_case_x:nnn} % 代替原来的 \cs{clist_if_in:NnTF} 来判断是否是行内环境。} % \begin{macrocode} \keys_define:nn { xeCJK / options } { InlineEnv .code:n = { \seq_set_from_clist:Nn \l_@@_inline_env_seq {#1} \@@_update_inline_env_case_tl: } , InlineEnv+ .code:n = { \clist_map_inline:nn {#1} { \seq_if_in:NnF \l_@@_inline_env_seq {##1} { \seq_put_right:Nn \l_@@_inline_env_seq {##1} } } \@@_update_inline_env_case_tl: } , InlineEnv- .code:n = { \clist_map_inline:nn {#1} { \seq_remove_all:Nn \l_@@_inline_env_seq {##1} } \@@_update_inline_env_case_tl: } } \seq_new:N \l_@@_inline_env_seq % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_update_inline_env_case_tl:} % \begin{macrocode} \cs_new_protected:Npn \@@_update_inline_env_case_tl: { \tl_clear:N \l_@@_inline_env_case_tl \seq_map_inline:Nn \l_@@_inline_env_seq { \tl_put_right:Nn \l_@@_inline_env_case_tl { {##1} { \use_ii:nn } } } } \tl_new:N \l_@@_inline_env_case_tl % \end{macrocode} % \end{macro} % % \begin{macro}{PlainEquation} % \changes{v3.1.1}{2012/12/06}{增加 \texttt{PlainEquation} 选项。} % \begin{macrocode} \keys_define:nn { xeCJK / options } { PlainEquation .bool_set:N = \l_@@_plain_equation_bool } % \end{macrocode} % \end{macro} % % \subsection{增加 CJK 子分区} % % \begin{macro}[internal]{\g_@@_CJK_sub_class_seq} % \begin{macrocode} \seq_new:N \g_@@_CJK_sub_class_seq % \end{macrocode} % \end{macro} % % \begin{macro}{\xeCJKDeclareSubCJKBlock} % 声明 CJK 子区范围,|#1| 为自定义名称,|#2| 为子区的 |Unicode| 范围。 % \begin{macrocode} \NewDocumentCommand \xeCJKDeclareSubCJKBlock { s > { \TrimSpaces } m > { \TrimSpaces } m } { \xeCJK_declare_sub_char_class:nxx { CJK } {#2} {#3} \IfBooleanT {#1} { \xeCJKResetPunctClass } } \@onlypreamble \xeCJKDeclareSubCJKBlock % \end{macrocode} % \end{macro} % % \begin{macro}{\xeCJKCancelSubCJKBlock,\xeCJKRestoreSubCJKBlock} % 取消和恢复对 CJK 子区的声明。 % \begin{macrocode} \bool_new:N \l_@@_sub_cancel_bool \NewDocumentCommand \xeCJKCancelSubCJKBlock { s m } { \bool_if:NF \l_@@_sub_cancel_bool { \bool_set_true:N \l_@@_sub_cancel_bool \@@_sub_restore_or_cancel:x {#2} \IfBooleanT {#1} { \xeCJKResetPunctClass } } } \NewDocumentCommand \xeCJKRestoreSubCJKBlock { s m } { \bool_if:NT \l_@@_sub_cancel_bool { \bool_set_false:N \l_@@_sub_cancel_bool \@@_sub_restore_or_cancel:x {#2} \IfBooleanT {#1} { \xeCJKResetPunctClass } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_sub_restore_or_cancel:n} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_sub_restore_or_cancel:n #1 { \clist_map_inline:nn {#1} { \int_if_exist:cTF { \@@_class_csname:n { CJK/##1 } } { \xeCJK_declare_char_class:nx { CJK \bool_if:NF \l_@@_sub_cancel_bool { /##1 } } { \tl_use:c { g_@@_CJK/##1_range_clist } } } { \@@_error:nx { SubBlock-undefined } {##1} } } } \cs_generate_variant:Nn \@@_sub_restore_or_cancel:n { x } \@@_msg_new:nn { SubBlock-undefined } { The~CJK~sub~block~`#1'~is~undefined.\\\\ Try~to~use~\token_to_str:N \xeCJKDeclareSubCJKBlock \ to~declare~it. } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_declare_sub_char_class:nnn} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_declare_sub_char_class:nnn #1#2#3 { \int_if_exist:cF { \@@_class_csname:n { #1/#2 } } { \xeCJK_new_class:n { #1/#2 } \@@_set_sub_class_toks:nn {#1} {#2} \xeCJK_new_sub_key:n {#2} } \xeCJK_declare_char_class:nn { #1/#2 } {#3} } \cs_generate_variant:Nn \xeCJK_declare_sub_char_class:nnn { nxx } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_set_sub_class_toks:nn} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_set_sub_class_toks:nn #1#2 { \seq_map_inline:Nn \g_@@_base_class_seq { \xeCJK_copy_inter_class_toks:nnnn { #1/#2 } {##1} {#1} {##1} \xeCJK_copy_inter_class_toks:nnnn {##1} { #1/#2 } {##1} {#1} \str_if_eq:nnTF {##1} { CJK } { \xeCJK_pre_inter_class_toks:nnn {##1} { #1/#2 } { \@@_switch_font:nn {#1} {#2} } } { \xeCJK_replace_inter_class_toks:nnnn {##1} { #1/#2 } { \CJKsymbol } { \@@_switch_font:nn {#1} {#2} \CJKsymbol } } } \xeCJK_copy_inter_class_toks:nnnn { #1/#2 } { #1/#2 } {#1} {#1} \seq_map_inline:Nn \g_@@_CJK_sub_class_seq { \xeCJK_copy_inter_class_toks:nnnn { #1/#2 } { #1/##1 } {#1} {#1} \xeCJK_copy_inter_class_toks:nnnn { #1/##1 } { #1/#2 } {#1} {#1} \xeCJK_pre_inter_class_toks:nnn { #1/#2 } { #1/##1 } { \@@_switch_font:nn {#2} {##1} } \xeCJK_pre_inter_class_toks:nnn { #1/##1 } { #1/#2 } { \@@_switch_font:nn {##1} {#2} } } \seq_gput_right:Nn \g_@@_CJK_sub_class_seq {#2} \@@_save_CJK_class:n { #1/#2 } \clist_map_inline:nn { CJK , FullLeft , FullRight } { \xeCJK_pre_inter_class_toks:nnn { #1/#2 } {##1} { \@@_switch_font:nn {#2} {#1} } } } % \end{macrocode} % \end{macro} % % \subsection{标点处理} % % \cs{XeTeXglyphbouds} 可以得到一个字符的左右边距,用于标点压缩。如果它不可用,则 % 在文档中只能使用 |plain| 这一标点格式原样输出标点。 % \begin{macrocode} \cs_if_exist:NF \XeTeXglyphbounds { \@@_msg_new:nn { XeTeX-too-old } { \token_to_str:N \XeTeXglyphbounds \ is~not~defined.\\ CJK~punctuation~kerning~will~not~be~available.\\\\ You~have~to~update~XeTeX~to~the~version~0.9995.0~or~later. } \@@_error:n { XeTeX-too-old } \AtEndOfPackage { \keys_define:nn { xeCJK / options } { PunctStyle / unknown .code:n = { \@@_error:nx { punct-style-unknown } { \l_keys_value_tl } } } \seq_gclear:N \g_@@_punct_style_seq \xeCJKsetup { PunctStyle = plain } } } % \end{macrocode} % % \begin{macro}{\xeCJKsetwidth} % 手动设置参数中的标点符号的宽度。 % \begin{macrocode} \NewDocumentCommand \xeCJKsetwidth { m m } { \tl_map_inline:xn {#1} { \tl_gset:cn { g_@@_punct_width/##1/tl } {#2} } } \cs_generate_variant:Nn \tl_map_inline:nn { x } % \end{macrocode} % \end{macro} % % \begin{macro}{\xeCJKsetkern} % 手动设置相邻标点的距离。 % \begin{macrocode} \NewDocumentCommand \xeCJKsetkern { m m m } { \tl_gset:cn { g_@@_punct/kern/#1/#2/tl } {#3} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal,var]{\c_@@_left_tl,\c_@@_right_tl} % \begin{macrocode} \tl_const:Nn \c_@@_left_tl { left } \tl_const:Nn \c_@@_right_tl { right } % \end{macrocode} % \end{macro} % % \begin{macro} % {AllowBreakBetweenPuncts, KaiMingPunct, LongPunct, MiddlePunct,PunctWidth} % 相关选项声明。 % \begin{macrocode} \keys_define:nn { xeCJK / options } { AllowBreakBetweenPuncts .choice: , AllowBreakBetweenPuncts / true .code:n = { \bool_set_true:N \l_@@_punct_breakable_bool \cs_set_eq:NN \xeCJK_punct_kern:NN \@@_punct_breakable_kern:NN } , AllowBreakBetweenPuncts / false .code:n = { \bool_set_false:N \l_@@_punct_breakable_bool \cs_set_eq:NN \xeCJK_punct_kern:NN \@@_punct_nobreak_kern:NN } , AllowBreakBetweenPuncts .default:n = { true } , KaiMingPunct .code:n = { \@@_set_special_punct:nn { mixed_width } {#1} } , KaiMingPunct+ .code:n = { \@@_add_special_punct:nn { mixed_width } {#1} } , KaiMingPunct- .code:n = { \@@_sub_special_punct:nn { mixed_width } {#1} } , LongPunct .code:n = { \@@_set_special_punct:nn { long } {#1} } , LongPunct+ .code:n = { \@@_add_special_punct:nn { long } {#1} } , LongPunct- .code:n = { \@@_sub_special_punct:nn { long } {#1} } , MiddlePunct .code:n = { \@@_set_special_punct:nn { middle } {#1} } , MiddlePunct+ .code:n = { \@@_add_special_punct:nn { middle } {#1} } , MiddlePunct- .code:n = { \@@_sub_special_punct:nn { middle } {#1} } , PunctWidth .tl_gset:N = \g_@@_punct_width_tl } \bool_new:N \l_@@_punct_breakable_bool % \end{macrocode} % \end{macro} % % 相关选项定义的辅助函数。 % \begin{macrocode} \clist_new:N \g_@@_special_punct_clist \clist_gset:Nn \g_@@_special_punct_clist { mixed_width , long , middle } \cs_new_nopar:Npn \@@_special_punct_seq:n #1 { g_@@_special_punct_#1_seq } \cs_new_nopar:Npn \@@_special_punct_tl:nN #1#2 { g_@@_special_punct_#1_#2_tl } \clist_map_inline:Nn \g_@@_special_punct_clist { \seq_new:c { \@@_special_punct_seq:n {#1} } } \cs_new_protected_nopar:Npn \@@_set_special_punct:nn #1#2 { \seq_map_inline:cn { \@@_special_punct_seq:n {#1} } { \cs_undefine:c { \@@_special_punct_tl:nN {#1} {##1} } } \seq_gclear:c { \@@_special_punct_seq:n {#1} } \tl_map_inline:xn {#2} { \tl_new:c { \@@_special_punct_tl:nN {#1} {##1} } \seq_gput_right:cn { \@@_special_punct_seq:n {#1} } {##1} } } \cs_new_protected_nopar:Npn \@@_add_special_punct:nn #1#2 { \tl_map_inline:xn {#2} { \seq_if_in:cnF { \@@_special_punct_seq:n {#1} } {##1} { \tl_new:c { \@@_special_punct_tl:nN {#1} {##1} } \seq_gput_right:cn { \@@_special_punct_seq:n {#1} } {##1} } } } \cs_new_protected_nopar:Npn \@@_sub_special_punct:nn #1#2 { \tl_map_inline:xn {#2} { \cs_undefine:c { \@@_special_punct_tl:nN {#1} {##1} } \seq_gremove_all:cn { \@@_special_punct_seq:n {#1} } {##1} } } % \end{macrocode} % % 判断一个标点符号是否为全角右标点和长标点符号。 % \begin{macrocode} \prg_new_conditional:Npnn \@@_punct_if_right:N #1 { p , T , F , TF } { \if_int_compare:w \xeCJK_token_value_class:N #1 = \xeCJK_class_num:n { FullRight } \prg_return_true: \else: \prg_return_false: \fi: } \clist_map_inline:Nn \g_@@_special_punct_clist { \exp_args:Nc \prg_new_conditional:Npnn { @@_punct_if_#1:N } ##1 { p , T , F , TF } { \if_cs_exist:w \@@_special_punct_tl:nN {#1} {##1} \cs_end: \prg_return_true: \else: \prg_return_false: \fi: } } % \end{macrocode} % % 一些用于记录的辅助函数。 % \begin{macrocode} \cs_new_nopar:Npn \@@_punct_dim_csname:nn #1#2 { c__\l_xeCJK_current_font_tl/\l_xeCJK_punct_style_tl/#1/#2/tl } \cs_new_nopar:Npn \@@_punct_dim_csname:nnn { \@@_punct_dim_csname:nnnn { \l_xeCJK_punct_style_tl } } \cs_new_nopar:Npn \@@_punct_dim_csname:nnnn #1#2#3#4 { c__\l_xeCJK_current_font_tl/#1/#2/#3/#4/tl } \cs_new_nopar:Npn \@@_use_punct_dim:nn #1#2 { \tl_use:c { \@@_punct_dim_csname:nn {#1} {#2} } } \cs_new_nopar:Npn \@@_use_punct_dim:nnn #1#2#3 { \tl_use:c { \@@_punct_dim_csname:nnn {#1} {#2} {#3} } } \cs_new_protected_nopar:Npn \@@_save_punct_dim:nnn #1#2#3 { \tl_const:cx { \@@_punct_dim_csname:nn {#1} {#2} } { \dim_eval:n {#3} } } \cs_new_protected_nopar:Npn \@@_save_punct_dim:nnnn #1#2#3#4 { \tl_const:cx { \@@_punct_dim_csname:nnn {#1} {#2} {#3} } { \dim_eval:n {#4} } } % \end{macrocode} % % \changes{v3.1.0}{2012/11/14}{使用 \pkg{xtemplate} 宏包的机制来组织标点符号的处理。} % % 定义标点处理模板。 % \begin{macrocode} \DeclareObjectType { xeCJK / punctuation } { \c_three } % \end{macrocode} % % \begin{macrocode} \DeclareTemplateInterface { xeCJK / punctuation } { basic } { \c_three } { enabled-global-setting : boolean = true , fixed-punct-width : length = \c_max_dim , fixed-punct-ratio : real = \c_one_fp , mixed-punct-width : length = \KeyValue { fixed-punct-width } , mixed-punct-ratio : real = \KeyValue { fixed-punct-ratio } , middle-punct-width : length = \KeyValue { fixed-punct-width } , middle-punct-ratio : real = \KeyValue { fixed-punct-ratio } , fixed-margin-width : length = \c_max_dim , fixed-margin-ratio : real = \c_one_fp , mixed-margin-width : length = \KeyValue { fixed-margin-width } , mixed-margin-ratio : real = \KeyValue { fixed-margin-ratio } , middle-margin-width : length = \KeyValue { fixed-margin-width } , middle-margin-ratio : real = \KeyValue { fixed-margin-ratio } , add-min-bound-to-margin : boolean = false , optimize-margin : boolean = false , margin-minimum : length = \c_zero_dim , enabled-kerning : boolean = true , min-bound-to-kerning : boolean = false , kerning-total-width : length = \c_max_dim , kerning-total-ratio : real = 0.75 , optimize-kerning : boolean = false , same-align-margin : length = \c_max_dim , same-align-ratio : real = \c_zero_fp , different-align-margin : length = \c_max_dim , different-align-ratio : real = \c_zero_fp , kerning-margin-width : length = \c_max_dim , kerning-margin-ratio : real = \c_one_fp , kerning-margin-minimum : length = \c_zero_dim } % \end{macrocode} % % \begin{macrocode} \DeclareTemplateCode { xeCJK / punctuation } { basic } { \c_three } { enabled-global-setting = \l_@@_enabled_global_setting_bool , fixed-punct-width = \l_@@_fixed_punct_width_dim , fixed-punct-ratio = \l_@@_fixed_punct_ratio_fp , mixed-punct-width = \l_@@_mixed_punct_width_dim , mixed-punct-ratio = \l_@@_mixed_punct_ratio_fp , middle-punct-width = \l_@@_middle_punct_width_dim , middle-punct-ratio = \l_@@_middle_punct_ratio_fp , fixed-margin-width = \l_@@_fixed_margin_width_dim , fixed-margin-ratio = \l_@@_fixed_margin_ratio_fp , mixed-margin-width = \l_@@_mixed_margin_width_dim , mixed-margin-ratio = \l_@@_mixed_margin_ratio_fp , middle-margin-width = \l_@@_middle_margin_width_dim , middle-margin-ratio = \l_@@_middle_margin_ratio_fp , add-min-bound-to-margin = \l_@@_add_min_bound_to_margin_bool , optimize-margin = \l_@@_optimize_margin_bool , margin-minimum = \l_@@_margin_minimum_dim , enabled-kerning = \l_@@_enabled_kerning_bool , min-bound-to-kerning = \l_@@_min_bound_to_kerning_bool , kerning-total-width = \l_@@_kerning_total_width_dim , kerning-total-ratio = \l_@@_kerning_total_ratio_fp , optimize-kerning = \l_@@_optimize_kerning_bool , same-align-margin = \l_@@_same_align_margin_dim , same-align-ratio = \l_@@_same_align_ratio_fp , different-align-margin = \l_@@_different_align_margin_dim , different-align-ratio = \l_@@_different_align_ratio_fp , kerning-margin-width = \l_@@_kerning_margin_width_dim , kerning-margin-ratio = \l_@@_kerning_margin_ratio_fp , kerning-margin-minimum = \l_@@_kerning_margin_minimum_dim } { \AssignTemplateKeys \tl_if_blank:nTF {#3} { \xeCJK_punct_margin_process:NN {#1} {#2} } { \xeCJK_punct_kerning_process:NN {#2} {#3} } } % \end{macrocode} % % \begin{macro}[internal]{\xeCJK_punct_margin_process:NN} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_punct_margin_process:NN #1#2 { \dim_set:Nn \l_@@_bound_dim { \@@_use_punct_dim:nnn { bound } {#1} {#2} } \dim_set:Nn \l_@@_reverse_bound_dim { \@@_use_punct_dim:nnn { bound } { \xeCJK_reverse:nnn {#1} \c_@@_left_tl \c_@@_right_tl } {#2} } \dim_set:Nn \l_@@_tmp_dim { \bool_if:NTF \l_@@_enabled_global_setting_bool { \cs_if_exist_use:cTF { g_@@_punct_width/#2/tl } { \use_none:n } { \xeCJK_if_blank_x:nTF \g_@@_punct_width_tl { \use:n } { \g_@@_punct_width_tl \use_none:n } } } { \use:n } { \@@_punct_if_middle:NTF {#2} { \@@_punct_width_or_ratio:nN { middle } {#2} } { \@@_punct_if_mixed_width:NTF {#2} { \@@_punct_width_or_ratio:nN { mixed } {#2} } { \@@_punct_width_or_ratio:nN { fixed } {#2} } } } } \@@_save_punct_dim:nnnn { glue } {#1} {#2} { \dim_max:nn { \l_@@_margin_minimum_dim } { \dim_compare:nNnTF \l_@@_tmp_dim < \c_max_dim { \@@_punct_if_middle:NTF {#2} { ( \l_@@_tmp_dim - ( \@@_use_punct_dim:nn { dimen } {#2} ) ) / \c_two } { \bool_if:NTF \l_@@_optimize_margin_bool { \dim_max:nn { \dim_min:nn \l_@@_bound_dim \l_@@_reverse_bound_dim } } { \use:n } { \l_@@_tmp_dim - \l_@@_reverse_bound_dim - ( \@@_use_punct_dim:nn { dimen } {#2} ) } } } { \bool_if:NTF \l_@@_optimize_margin_bool { \dim_min:nn { \l_@@_bound_dim } } { \use:n } { \@@_punct_if_middle:NTF {#2} { \dim_compare:nNnTF \l_@@_middle_margin_width_dim < \c_max_dim { \l_@@_middle_margin_width_dim } { \fp_use:N \l_@@_middle_margin_ratio_fp \etex_dimexpr:D ( \l_@@_bound_dim + \l_@@_reverse_bound_dim ) / \c_two \scan_stop: } } { \@@_punct_if_mixed_width:NTF {#2} { \@@_margin_width_or_ratio:n { mixed } } { \@@_margin_width_or_ratio:n { fixed } } } } } } } } \dim_new:N \l_@@_bound_dim \dim_new:N \l_@@_reverse_bound_dim % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_punct_width_or_ratio:nN} % \begin{macrocode} \cs_new_nopar:Npn \@@_punct_width_or_ratio:nN #1#2 { \dim_compare:nNnTF { \use:c { l_@@_#1_punct_width_dim } } < \c_max_dim { \use:c { l_@@_#1_punct_width_dim } } { \fp_compare:nNnTF { \use:c { l_@@_#1_punct_ratio_fp } } = \c_zero_fp { \c_max_dim } { \fp_use:c { l_@@_#1_punct_ratio_fp } \etex_dimexpr:D \@@_use_punct_dim:nn { width } {#2} \scan_stop: } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_margin_width_or_ratio:n} % \begin{macrocode} \cs_new_nopar:Npn \@@_margin_width_or_ratio:n #1 { \dim_compare:nNnTF { \use:c { l_@@_#1_margin_width_dim } } < \c_max_dim { \use:c { l_@@_#1_margin_width_dim } } { \fp_use:c { l_@@_#1_margin_ratio_fp } \etex_dimexpr:D \l_@@_bound_dim \scan_stop: } \bool_if:NT \l_@@_add_min_bound_to_margin_bool { + \dim_min:nn \l_@@_bound_dim \l_@@_reverse_bound_dim } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_punct_kerning_process:NN} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_punct_kerning_process:NN #1#2 { \@@_save_punct_dim:nnnn { kern } {#1} {#2} { \bool_if:nTF { \l_@@_enabled_global_setting_bool && \tl_if_exist_p:c { g_@@_punct/kern/#1/#2/tl } } { \tl_use:c { g_@@_punct/kern/#1/#2/tl } } { \bool_if:NTF \l_@@_enabled_kerning_bool { \@@_calc_kerning_margin:NN {#1} {#2} } { \@@_original_kerning_margin:NN {#1} {#2} } } - ( \@@_use_punct_dim:nnn { bound } \c_@@_right_tl {#1} ) - ( \@@_use_punct_dim:nnn { bound } \c_@@_left_tl {#2} ) } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_original_kerning_margin:NN} % 相邻两个标点符号之间的本来空白宽度。 % \begin{macrocode} \cs_new_nopar:Npn \@@_original_kerning_margin:NN #1#2 { \dim_eval:n { \@@_use_punct_dim:nnn { \@@_punct_if_right:NTF {#1} { glue } { bound } } { \c_@@_right_tl } {#1} + \@@_use_punct_dim:nnn { \@@_punct_if_right:NTF {#2} { bound } { glue } } { \c_@@_left_tl } {#2} } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_calc_kerning_margin:NN} % \begin{macrocode} \cs_new_nopar:Npn \@@_calc_kerning_margin:NN #1#2 { \dim_max:nn { \l_@@_kerning_margin_minimum_dim } { \bool_if:NTF \l_@@_min_bound_to_kerning_bool { \@@_punct_min_bound:NN {#1} {#2} } { \bool_if:NTF \l_@@_optimize_kerning_bool { \dim_max:nn { \@@_punct_min_bound:NN {#1} {#2} } } { \use:n } { \dim_compare:nNnTF \l_@@_kerning_total_width_dim < \c_max_dim { \@@_calc_kerning_margin:nNN \l_@@_kerning_total_width_dim } { \fp_compare:nNnTF \l_@@_kerning_total_ratio_fp = \c_zero_fp { \xeCJK_if_same_class:NNTF {#1} {#2} { \@@_kerning_width_or_ratio:nNN { same } } { \@@_kerning_width_or_ratio:nNN { different } } } { \@@_calc_kerning_margin:nNN { \fp_use:N \l_@@_kerning_total_ratio_fp \etex_dimexpr:D \@@_use_punct_dim:nn { width } {#1} + \@@_use_punct_dim:nn { width } {#2} \scan_stop: } } } {#1} {#2} } } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_kerning_width_or_ratio:nNN} % \begin{macrocode} \cs_new_nopar:Npn \@@_kerning_width_or_ratio:nNN #1#2#3 { \dim_compare:nNnTF { \use:c { l_@@_#1_align_margin_dim } } < \c_max_dim { \use:c { l_@@_#1_align_margin_dim } \use_none:nn } { \fp_compare:nNnTF { \use:c { l_@@_#1_align_ratio_fp } } = \c_zero_fp { \use:n } { \fp_use:c { l_@@_#1_align_ratio_fp } \use_ii:nn } } { \dim_compare:nNnTF \l_@@_kerning_margin_width_dim < \c_max_dim { \l_@@_kerning_margin_width_dim \use_none:n } { \fp_use:N \l_@@_kerning_margin_ratio_fp \use:n } } { \etex_dimexpr:D \@@_original_kerning_margin:NN {#2} {#3} \scan_stop: } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_punct_min_bound:NN} % \begin{macrocode} \cs_new_nopar:Npn \@@_punct_min_bound:NN #1#2 { \dim_max:nn { \dim_min:nn { \@@_use_punct_dim:nnn { bound } \c_@@_left_tl {#1} } { \@@_use_punct_dim:nnn { bound } \c_@@_right_tl {#1} } } { \dim_min:nn { \@@_use_punct_dim:nnn { bound } \c_@@_left_tl {#2} } { \@@_use_punct_dim:nnn { bound } \c_@@_right_tl {#2} } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_calc_kerning_margin:nNN} % |#2| 和 |#3| 为相邻的两个标点,|#1| 为要确定的相邻两个标点总共占的宽度。 % \begin{macrocode} \cs_new_nopar:Npn \@@_calc_kerning_margin:nNN #1#2#3 { \dim_eval:n { (#1) - ( \@@_use_punct_dim:nnn { \@@_punct_if_right:NTF {#2} { bound } { glue } } { \c_@@_left_tl } {#2} ) - ( \@@_use_punct_dim:nnn { \@@_punct_if_right:NTF {#3} { glue } { bound } } { \c_@@_right_tl } {#3} ) - ( \@@_use_punct_dim:nn { dimen } {#2} ) - ( \@@_use_punct_dim:nn { dimen } {#3} ) } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_get_punct_bounds:NN} % |#1| 为 \cs{c_@@_left_tl} 或 \cs{c_@@_right_tl},|#2| 为标点符号。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_get_punct_bounds:NN #1#2 { \tl_if_exist:cF { \@@_punct_dim_csname:nnn { glue } {#1} {#2} } { \tl_if_eq:NNTF \l_xeCJK_punct_style_tl \c_@@_punct_style_plain_tl { \@@_save_punct_dim:nnnn { glue } {#1} {#2} { \c_zero_dim } \@@_save_punct_dim:nnnn { bound } \c_@@_left_tl {#2} { \c_zero_dim } \@@_save_punct_dim:nnnn { bound } \c_@@_right_tl {#2} { \c_zero_dim } } { { \xeCJK_select_font: \xeCJK_calc_punct_dimen:f {#2} } \@@_punct_if_long:NTF {#2} { \@@_save_punct_dim:nnnn { glue } {#1} {#2} { \c_zero_dim } } { \UseInstance { xeCJK / punctuation } { \l_xeCJK_punct_style_tl } {#1} {#2} { } } } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_calc_punct_dimen:N} % 计算标点的左右实际边距和实际尺寸。对于破折号,计算两标点之间的空白,保证它中间 % 不被断开。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_calc_punct_dimen:N #1 { \@@_save_punct_dim:nnnn { bound } \c_@@_left_tl {#1} { \xeCJK_glyph_bounds:NN \c_one {#1} } \@@_save_punct_dim:nnnn { bound } \c_@@_right_tl {#1} { \xeCJK_glyph_bounds:NN \c_three {#1} } \dim_set:Nn \l_@@_tmp_dim { ( \@@_use_punct_dim:nnn { bound } \c_@@_left_tl {#1} ) + ( \@@_use_punct_dim:nnn { bound } \c_@@_right_tl {#1} ) } \@@_save_punct_dim:nnn { width } {#1} { \etex_fontcharwd:D \tex_font:D \xeCJK_token_value_charcode:N #1 } \@@_save_punct_dim:nnn { dimen } {#1} { \@@_use_punct_dim:nn { width } {#1} - \l_@@_tmp_dim } \@@_punct_if_long:NT {#1} { \@@_save_punct_dim:nnnn { kern } {#1} {#1} { \bool_if:nTF { \str_if_eq_p:nn {#1} { ^^^^2025 } || \str_if_eq_p:nn {#1} { ^^^^2026 } } { \c_zero_dim } { - \l_@@_tmp_dim } } } } \cs_generate_variant:Nn \xeCJK_calc_punct_dimen:N { f } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_glyph_bounds:NN} % 用 \cs{XeTeXglyphbounds} 取得标点符号的上下左右空白。 % \begin{macrocode} \cs_new_nopar:Npn \xeCJK_glyph_bounds:NN #1#2 { \dim_use:N \XeTeXglyphbounds #1 ~ \XeTeXcharglyph \xeCJK_token_value_charcode:N #2 \exp_stop_f: } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_get_punct_kerning:NN} % 标点挤压。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_get_punct_kerning:NN #1#2 { \tl_if_exist:cF { \@@_punct_dim_csname:nnn { kern } {#1} {#2} } { \tl_if_eq:NNTF \l_xeCJK_punct_style_tl \c_@@_punct_style_plain_tl { \@@_save_punct_dim:nnnn { kern } {#1} {#2} { \c_zero_dim } } { \UseInstance { xeCJK / punctuation } { \l_xeCJK_punct_style_tl } { } {#1} {#2} } } } \cs_generate_variant:Nn \xeCJK_get_punct_kerning:NN { o } % \end{macrocode} % \end{macro} % % \begin{macro}{PunctStyle} % \begin{macrocode} \keys_define:nn { xeCJK / options } { PunctStyle .choice: , PunctStyle .default:n = { quanjiao } , PunctStyle / halfwidth .meta:n = { PunctStyle = banjiao } , PunctStyle / fullwidth .meta:n = { PunctStyle = quanjiao } , PunctStyle / mixedwidth .meta:n = { PunctStyle = kaiming } , PunctStyle / marginkerning .meta:n = { PunctStyle = hangmobanjiao } , PunctStyle / plain .code:n = { \tl_set_eq:NN \l_xeCJK_punct_style_tl \c_@@_punct_style_plain_tl } , PunctStyle / unknown .code:n = { \IfInstanceExistTF { xeCJK / punctuation } { \l_keys_value_tl } { \tl_set:Nx \l_xeCJK_punct_style_tl { \l_keys_value_tl } } { \@@_error:nx { punct-style-unknown } { \l_keys_value_tl } } } } \tl_new:N \l_xeCJK_punct_style_tl \tl_const:Nn \c_@@_punct_style_plain_tl { plain } \@@_msg_new:nn { punct-style-unknown } { Punctuation~style~"#1"~is~unknown. \\\\ The~available~styles~are~listed~as~follow.\\\\ "plain,~\seq_use:Nnnn \g_@@_punct_style_seq { ~and~ } { ,~ } { ,~and~ }".\\ } % \end{macrocode} % \end{macro} % % \begin{macro}{\xeCJKDeclarePunctStyle} % 定义新的标点处理风格,已经存在的同名风格将被覆盖。 % \begin{macrocode} \NewDocumentCommand \xeCJKDeclarePunctStyle { > { \TrimSpaces } m m } { \IfInstanceExistTF { xeCJK / punctuation } {#1} { \@@_warning:nx { punct-style-already-defined } {#1} } { \seq_gput_right:Nx \g_@@_punct_style_seq {#1} } \exp_args:Nnx \DeclareInstance { xeCJK / punctuation } {#1} { basic } {#2} } \seq_new:N \g_@@_punct_style_seq \@@_msg_new:nn { punct-style-already-defined } { Punctuation~style~"#1"~is~already~defined!. \\\\ The~existing~style~of~"#1"~will~be~overwritten.\\ } \@onlypreamble \xeCJKDeclarePunctStyle % \end{macrocode} % \end{macro} % % \begin{macro}{\xeCJKEditPunctStyle} % 对已有的标点处理风格进行修改。 % \begin{macrocode} \NewDocumentCommand \xeCJKEditPunctStyle { > { \TrimSpaces } m m } { \IfInstanceExistTF { xeCJK / punctuation } {#1} { \exp_args:Nnx \EditInstance { xeCJK / punctuation } {#1} {#2} } { \@@_error:nx { punct-style-unknown } {#1} } } \@onlypreamble \xeCJKEditPunctStyle % \end{macrocode} % \end{macro} % % 默认设置即为全角格式。 % \begin{macrocode} \xeCJKDeclarePunctStyle { quanjiao } { } % \end{macrocode} % % \begin{macrocode} \xeCJKDeclarePunctStyle { hangmobanjiao } { enabled-kerning = false } % \end{macrocode} % % \begin{macrocode} \xeCJKDeclarePunctStyle { banjiao } { fixed-punct-ratio = 0.5 , optimize-margin = true , kerning-total-ratio = 0.5 , optimize-kerning = true } % \end{macrocode} % % \begin{macrocode} \xeCJKDeclarePunctStyle { kaiming } { fixed-punct-ratio = 0.5 , mixed-punct-ratio = 0.8 , optimize-margin = true , kerning-total-ratio = 0.5 , optimize-kerning = true } % \end{macrocode} % % \begin{macrocode} \xeCJKDeclarePunctStyle { CCT } { fixed-punct-ratio = 0.7 , optimize-margin = true , kerning-total-ratio = 0.6 , optimize-kerning = true } % \end{macrocode} % % \subsection{后备字体} % % \begin{macro}{AutoFallBack} % 后备字体的宏包选项声明。 % \begin{macrocode} \keys_define:nn { xeCJK / options } { AutoFallBack .choice: , AutoFallBack / true .code:n = { \cs_if_eq:NNF \CJKsymbol \xeCJK_fallback_test_glyph:N { \cs_set_eq:NN \@@_fallback_save_CJKsymbol:N \CJKsymbol \cs_set_eq:NN \CJKsymbol \xeCJK_fallback_test_glyph:N } } , AutoFallBack / false .code:n = { \cs_if_eq:NNT \CJKsymbol \xeCJK_fallback_test_glyph:N { \cs_set_eq:NN \CJKsymbol \@@_fallback_save_CJKsymbol:N } } , AutoFallBack .default:n = { true } , fallback .meta:n = { AutoFallBack = true } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_fallback_test_glyph:N} % 测试当前字体中是否存在当前字符,如存在则直接输出,否则启用后备字体。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_fallback_test_glyph:N #1 { \xeCJK_glyph_if_exist:NTF {#1} { \@@_fallback_save_CJKsymbol:N {#1} } { \xeCJK_class_group_begin: \tl_set_eq:NN \l_@@_fallback_family_tl \l_xeCJK_family_tl \xeCJK_fallback_loop:Nn {#1} { \l_@@_fallback_family_tl/FallBack } \xeCJK_class_group_end: } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_fallback_loop:Nn} % \changes{v3.1.0}{2012/11/19}{调整备用字体的循环方式。} % \changes{v3.2.4}{2013/06/30} % {使 \cs{CJKfamilydefault} 的 \texttt{FallBack} 设置全局可用。} % 循环测试后备字体是否包含字符 |#1|。若后备字体中存在该字符或者再没有后备字体,则 % 结束循环。当前字体族没有备用字体时,使用 \cs{CJKfamilydefault} 的设置。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_fallback_loop:Nn #1#2 { \xeCJK_family_if_exist:xTF {#2} { \xeCJK_select_font:x {#2} \tl_set:Nx \l_@@_fallback_family_tl {#2} \xeCJK_glyph_if_exist:NTF {#1} { \@@_fallback_save_CJKsymbol:N {#1} } { \xeCJK_fallback_loop:Nn {#1} { \l_@@_fallback_family_tl/FallBack } } } { \str_if_eq_x:nnTF { \CJKfamilydefault } { \l_xeCJK_family_tl } { \@@_warning:nxxx { missing-glyph } { \l_@@_fallback_family_tl } {#1} { \int_to_hexadecimal:n { `#1 } } \@@_fallback_save_CJKsymbol:N {#1} } { \tl_set:Nx \l_xeCJK_family_tl { \CJKfamilydefault } \xeCJK_fallback_loop:Nn {#1} { \l_xeCJK_family_tl } } } } \@@_msg_new:nn { missing-glyph } { CJKfamily~`\@@_msg_family_map:n {#1}'~ ( \prop_get:Nn \g_@@_family_font_name_prop {#1} )~ does~not~contain~glyph~`#2'~(U+#3).\\ } % \end{macrocode} % \end{macro} % % \begin{macro}{\setCJKfallbackfamilyfont} % \begin{macrocode} \NewDocumentCommand \setCJKfallbackfamilyfont { m O { } m } { \use:x { \xeCJK_set_family_fallback:nnn {#1} {#2} {#3} } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_set_family_fallback:nnn} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_set_family_fallback:nnn #1#2#3 { \group_begin: \tl_set:Nn \l_@@_fallback_family_tl {#1} \prop_get:NVNF \g_@@_family_font_name_prop \l_@@_fallback_family_tl \l_@@_font_name_tl { \tl_clear:N \l_@@_font_name_tl } \clist_map_inline:nn {#3} { \tl_put_right:Nn \l_@@_fallback_family_tl { /FallBack } \@@_get_sub_features:Vn \l_@@_fallback_family_tl {##1} \clist_put_left:Nn \l_@@_sub_font_options_clist {#2} \xeCJK_set_family:VVV \l_@@_fallback_family_tl \l_@@_sub_font_options_clist \l_@@_sub_font_name_tl } \group_end: } \tl_new:N \l_@@_fallback_family_tl % \end{macrocode} % \end{macro} % % % \subsection{CJK 字体族声明方式} % % \begin{macrocode} \bool_new:N \g_@@_auto_fake_bold_bool \bool_new:N \g_@@_auto_fake_slant_bool \fp_new:N \g_@@_embolden_factor_fp \fp_new:N \g_@@_slant_factor_fp % \end{macrocode} % % \begin{macro}{AutoFakeBold, AutoFakeSlant,EmboldenFactor,SlantFactor} % 伪粗体和伪斜体的宏包选项声明。 % \begin{macrocode} \keys_define:nn { xeCJK / options } { AutoFakeBold .choices:nn = { true , false } { \use:c { bool_gset_ \l_keys_choice_tl :N } \g_@@_auto_fake_bold_bool } , AutoFakeBold / unknown .code:n = { \bool_gset_true:N \g_@@_auto_fake_bold_bool \fp_gset:Nn \g_@@_embolden_factor_fp { \l_keys_value_tl } } , AutoFakeBold .default:n = { true } , AutoFakeSlant .choices:nn = { true , false } { \use:c { bool_gset_ \l_keys_choice_tl :N } \g_@@_auto_fake_slant_bool } , AutoFakeSlant / unknown .code:n = { \bool_gset_true:N \g_@@_auto_fake_slant_bool \fp_gset:Nn \g_@@_slant_factor_fp { \l_keys_value_tl } } , AutoFakeSlant .default:n = { true } , EmboldenFactor .fp_gset:N = \g_@@_embolden_factor_fp , SlantFactor .fp_gset:N = \g_@@_slant_factor_fp , BoldFont .meta:n = { AutoFakeBold = true } , boldfont .meta:n = { AutoFakeBold = true } , SlantFont .meta:n = { AutoFakeSlant = true } , slantfont .meta:n = { AutoFakeSlant = true } } % \end{macrocode} % \end{macro} % % \changes{v3.2.4}{2013/07/02}{内部调整分区字体的设置方法。} % % \begin{macro}[internal]{\xeCJK_new_sub_key:n,\g_@@_sub_key_seq} % 用于定义 CJK 子区字体和备用字体的选项。 % \begin{macrocode} \seq_new:N \g_@@_sub_key_seq \cs_new_protected_nopar:Npn \xeCJK_new_sub_key:n #1 { \seq_gput_right:Nn \g_@@_sub_key_seq {#1} \keys_define:nn { xeCJK / features } { #1 .code:n = { \tl_if_blank:nTF {##1} { \prop_clear:N \l_@@_sub_key_prop \tl_put_right:Nn \l_@@_family_name_tl { /#1 } \clist_remove_all:Nn \l_@@_font_options_clist {#1} } { \str_if_eq:nnTF {##1} { * } { \prop_put:Nnn \l_@@_sub_key_prop {#1} { \q_no_value } } { \@@_get_sub_features:nn {#1} {##1} } } } , #1 .default:n = { } } } % \end{macrocode} % \end{macro} % % \changes{v3.2.4}{2013/07/02}{改进获取分区字体属性的办法。} % % \begin{macro}[internal]{\@@_get_sub_features:nn,\@@_get_sub_features:w} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_get_sub_features:nn #1#2 { \tl_set:Nx \l_@@_tmp_tl { \xeCJK_tl_remove_outer_braces:n {#2} } \clist_clear:N \l_@@_sub_font_options_clist \exp_after:wN \@@_get_sub_features:w \l_@@_tmp_tl \q_mark [ \q_nil ] \q_mark \q_stop \tl_if_empty:NTF \l_@@_sub_font_name_tl { \tl_set_eq:NN \l_@@_sub_font_name_tl \l_@@_font_name_tl } { \tl_replace_all:NnV \l_@@_sub_font_name_tl { * } \l_@@_font_name_tl } \prop_put:Nnx \l_@@_sub_key_prop {#1} { { \exp_not:V \l_@@_sub_font_options_clist } { \exp_not:V \l_@@_sub_font_name_tl } } } \cs_new_protected_nopar:Npn \@@_get_sub_features:w #1 [#2] #3 \q_mark #4 \q_stop { \quark_if_nil:nTF {#2} { \tl_set_eq:NN \l_@@_sub_font_name_tl \l_@@_tmp_tl } { \tl_set:Nx \l_@@_sub_font_name_tl { \xeCJK_tl_remove_outer_braces:n {#3} } \tl_if_empty:NTF \l_@@_sub_font_name_tl { \tl_set_eq:NN \l_@@_sub_font_name_tl \l_@@_tmp_tl } { \clist_set:Nn \l_@@_sub_font_options_clist {#2} } } } \tl_new:N \l_@@_sub_family_name_tl \tl_new:N \l_@@_sub_font_name_tl \clist_new:N \l_@@_sub_font_options_clist \cs_generate_variant:Nn \@@_get_sub_features:nn { V } \cs_generate_variant:Nn \tl_replace_all:Nnn { NnV } % \end{macrocode} % \end{macro} % % \begin{macro}{FallBack} % \begin{macrocode} \xeCJK_new_sub_key:n { FallBack } % \end{macrocode} % \end{macro} % % \begin{macro}[internal] % {\g_@@_features_id_prop, BoldFont, ItalicFont, BoldItalicFont, % SlantedFont, BoldSlantedFont,BoldFeatures, ItalicFeatures, % BoldItalicFeatures, SlantedFeatures, BoldSlantedFeatures} % 调用字体的属性声明,同 \pkg{fontspec} 宏包。 % \begin{macrocode} \prop_new:N \g_@@_features_id_prop \prop_put:Nnn \g_@@_features_id_prop { bf } { Bold } \prop_put:Nnn \g_@@_features_id_prop { it } { Italic } \prop_put:Nnn \g_@@_features_id_prop { bfit } { BoldItalic } \prop_put:Nnn \g_@@_features_id_prop { sl } { Slanted } \prop_put:Nnn \g_@@_features_id_prop { bfsl } { BoldSlanted } \prop_map_inline:Nn \g_@@_features_id_prop { \keys_define:nn { xeCJK / features } { #2Font .tl_set:c = { l_@@_font_name_#1_tl } , #2Features .clist_set:c = { l_@@_font_feat_#1_clist } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{AutoFakeBold, AutoFakeSlant} % \begin{macrocode} \keys_define:nn { xeCJK / features } { AutoFakeBold .choice: , AutoFakeBold / false .code:n = { \bool_set_false:N \l_@@_auto_fake_bold_bool } , AutoFakeBold / unknown .code:n = { \bool_set_true:N \l_@@_auto_fake_bold_bool \fp_set:Nn \l_@@_embolden_factor_fp { \l_keys_value_tl } } , AutoFakeBold .default:n = { \g_@@_embolden_factor_fp } , AutoFakeSlant .choice: , AutoFakeSlant / false .code:n = { \bool_set_false:N \l_@@_auto_fake_slant_bool } , AutoFakeSlant / unknown .code:n = { \bool_set_true:N \l_@@_auto_fake_slant_bool \fp_set:Nn \l_@@_slant_factor_fp { \l_keys_value_tl } } , AutoFakeSlant .default:n = { \g_@@_slant_factor_fp } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_set_family_initial:} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_set_family_initial: { \int_gincr:N \g_@@_family_int \prop_clear:N \l_@@_add_font_prop \prop_clear:N \l_@@_sub_key_prop \prop_map_inline:Nn \g_@@_features_id_prop { \tl_clear:c { l_@@_font_name_##1_tl } \clist_clear:c { l_@@_font_feat_##1_clist } } \clist_clear:N \l_@@_fontspec_options_clist \bool_set_eq:NN \l_@@_auto_fake_bold_bool \g_@@_auto_fake_bold_bool \bool_set_eq:NN \l_@@_auto_fake_slant_bool \g_@@_auto_fake_slant_bool \fp_set_eq:NN \l_@@_embolden_factor_fp \g_@@_embolden_factor_fp \fp_set_eq:NN \l_@@_slant_factor_fp \g_@@_slant_factor_fp } \int_new:N \g_@@_family_int \prop_new:N \l_@@_add_font_prop \prop_new:N \l_@@_sub_key_prop \clist_new:N \l_@@_fontspec_options_clist \bool_new:N \l_@@_auto_fake_bold_bool \bool_new:N \l_@@_auto_fake_slant_bool \fp_new:N \l_@@_embolden_factor_fp \fp_new:N \l_@@_slant_factor_fp % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_set_family:nnn} % 设置一个 CJK 新字体族,与 \cs{newfontfamily} 类似,增加 |FallBack| 选项。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_set_family:nnn #1#2#3 { \group_begin: \@@_set_family_initial: \tl_set:Nn \l_@@_family_name_tl {#1} \clist_set:Nn \l_@@_font_options_clist {#2} \tl_set:Nn \l_@@_font_name_tl {#3} \clist_concat:NNN \l_@@_font_options_clist \g_@@_default_features_clist \l_@@_font_options_clist \@@_remove_duplicate_keys:N \l_@@_font_options_clist \keys_set_known:nVN { xeCJK / features } \l_@@_font_options_clist \l_@@_fontspec_options_clist \@@_parse_features: \@@_pass_features: \@@_check_family:V \l_@@_family_name_tl \@@_gset_family_cs:x { \l_@@_family_name_tl } \@@_save_family_info: \@@_set_sub_block_family: \group_end: } \tl_new:N \l_@@_family_name_tl \tl_new:N \l_@@_font_name_tl \clist_new:N \l_@@_font_options_clist \cs_generate_variant:Nn \xeCJK_set_family:nnn { Vnn , VVV , Voo } \cs_new_protected_nopar:Npn \xeCJK_set_family:xxx #1#2#3 { \use:x { \xeCJK_set_family:nnn {#1} {#2} {#3} } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_remove_duplicate_keys:N} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_remove_duplicate_keys:N #1 { \prop_clear:N \l_@@_font_options_prop \keyval_parse:NNV \@@_prop_put_aux:n \@@_prop_put_aux:nn #1 \clist_clear:N #1 \prop_map_inline:Nn \l_@@_font_options_prop { \tl_set:No \l_@@_tmp_tl { \use_ii:nn ##2 } \tl_if_blank:VTF \l_@@_tmp_tl { \clist_put_right:No #1 { \use_i:nn ##2 } } { \clist_put_right:Nx #1 { \exp_not:o { \use_i:nn ##2 } = { \exp_not:V \l_@@_tmp_tl } } } } } \prop_new:N \l_@@_font_options_prop \cs_generate_variant:Nn \keyval_parse:NNn { NNV } \cs_new_protected_nopar:Npn \@@_prop_put_aux:n #1 { \prop_put:Nnn \l_@@_font_options_prop {#1} { {#1} { } } } \cs_new_protected_nopar:Npn \@@_prop_put_aux:nn #1#2 { \prop_put:Nnn \l_@@_font_options_prop {#1} { {#1} {#2} } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_gset_family_cs:x} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_gset_family_cs:x #1 { \cs_gset_protected_nopar:cpx { \@@_family_csname:n {#1} } { \group_begin: \exp_not:n { \cs_set_eq:NN \@@_update_family:n \use_none:n } \exp_not:n { \fontspec_set_family:Nnn \l_@@_fontspec_family_tl } { \exp_not:V \l_@@_fontspec_options_clist } { \exp_not:V \l_@@_font_name_tl } \@@_gset_family_nfss_cs:xx {#1} { \exp_not:N \l_@@_fontspec_family_tl } \group_end: } } \tl_new:N \l_@@_fontspec_family_tl % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_check_family:n} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_check_family:n #1 { \prop_get:NnNT \g_@@_family_font_name_prop {#1} \l_@@_tmp_tl { \prop_gpop:NnNT \g_@@_family_name_prop {#1} \l_@@_tmp_tl { \cs_undefine:c { \@@_family_nfss_csname:n {#1} } } \@@_warning:nxx { CJKfamily-redef } {#1} { \l_@@_tmp_tl } } } \cs_generate_variant:Nn \@@_check_family:n { V } \@@_msg_new:nn { CJKfamily-redef } { Redefining~CJKfamily~`\@@_msg_family_map:n {#1}'~(#2). } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_add_font:nn,\@@_add_font_if_new:nn} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_add_font:nn #1#2 { \prop_put:Nnn \l_@@_add_font_prop { #1 Font } {#2} } \cs_new_protected_nopar:Npn \@@_add_font_if_new:nn #1#2 { \prop_put_if_new:Nnn \l_@@_add_font_prop { #1 Font } {#2} } \cs_generate_variant:Nn \@@_add_font:nn { nx , nV , nv } \cs_generate_variant:Nn \@@_add_font_if_new:nn { nx , nV , nv } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_add_fake_bold:n,\@@_add_fake_slant:n} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_add_fake_bold:n #1 { \clist_put_left:cx { l_@@_font_feat_#1_clist } { FakeBold = { \fp_use:N \l_@@_embolden_factor_fp } } } \cs_new_protected_nopar:Npn \@@_add_fake_slant:n #1 { \clist_put_left:cx { l_@@_font_feat_#1_clist } { FakeSlant = { \fp_use:N \l_@@_slant_factor_fp } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_parse_features:,\@@_parse_features:nn} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_parse_features: { \prop_map_function:NN \g_@@_features_id_prop \@@_parse_features:nn } \cs_new_protected_nopar:Npn \@@_parse_features:nn #1#2 { \@@_if_font_select:nTF {#1} { \@@_add_font:nv {#2} { l_@@_font_name_#1_tl } \@@_if_it_or_sl:nTF {#1} { \@@_if_font_select:nF { bf #1 } { \@@_add_font_if_new:nv {#2} { l_@@_font_name_#1_tl } } } { \str_if_eq:nnT {#1} { bf } { \@@_if_font_select:nF { bfit } { \@@_add_font:nV { BoldItalic } \l_@@_font_name_bf_tl } \@@_if_font_select:nF { bfsl } { \@@_add_font:nV { BoldSlanted } \l_@@_font_name_bf_tl } } } } { \@@_set_fake_font:nn {#1} {#2} } } % \end{macrocode} % \end{macro} % % \begin{macro}[pTF,internal]{\@@_if_font_select:n,\@@_if_it_or_sl:n} % \begin{macrocode} \prg_new_conditional:Npnn \@@_if_font_select:n #1 { p , T , F , TF } { \tl_if_blank:vTF { l_@@_font_name_#1_tl } { \prg_return_false: } { \prg_return_true: } } \prg_new_conditional:Npnn \@@_if_it_or_sl:n #1 { p , T , F , TF } { \if_predicate:w \bool_if_p:n { \str_if_eq_p:nn { it } {#1} || \str_if_eq_p:nn { sl } {#1} } \prg_return_true: \else: \prg_return_false: \fi: } \cs_generate_variant:Nn \tl_if_blank:nTF { v } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_set_fake_font:nn} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_set_fake_font:nn #1#2 { \str_if_eq:nnTF {#1} { bf } { \bool_if:NT \l_@@_auto_fake_bold_bool { \@@_add_fake_bold:n {#1} } } { \bool_if:NTF \l_@@_auto_fake_slant_bool { \bool_if:nT { \@@_if_it_or_sl_p:n {#1} || ( \str_if_eq_p:nn {#1} { bfit } && ! ( \@@_if_font_select_p:n { it } ) ) || ( \str_if_eq_p:nn {#1} { bfsl } && ! ( \@@_if_font_select_p:n { sl } ) ) } { \@@_add_fake_slant:n {#1} } } { \@@_if_it_or_sl:nT {#1} { \@@_map_it_sl:nn {#1} {#2} } } \bool_if:nT { \l_@@_auto_fake_bold_bool && ! ( \@@_if_it_or_sl_p:n {#1} ) && ! ( \@@_if_font_select_p:n { bf } ) } { \@@_add_fake_bold:n {#1} } } \@@_add_font_if_new:nn {#2} { * } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_map_it_sl:n} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_map_it_sl:nn #1#2 { \@@_if_map_font_select:nT {#1} { \@@_add_font:nx {#2} { \@@_get_map_font:n {#1} } \@@_if_font_select:nF { bf #1 } { \@@_add_font_if_new:nx { Bold #2 } { \@@_get_map_font:n {#1} } } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_get_map_font:n} % \begin{macrocode} \cs_new_nopar:Npn \@@_get_map_font:n #1 { \exp_not:v { l_@@_font_name_ \xeCJK_reverse:nnn {#1} { it } { sl } _tl } } % \end{macrocode} % \end{macro} % % \begin{macro}[pTF,internal]{\@@_if_map_font_select:n} % \begin{macrocode} \prg_new_conditional:Npnn \@@_if_map_font_select:n #1 { p , T , F , TF } { \xeCJK_if_blank_x:nTF { \@@_get_map_font:n {#1} } { \prg_return_false: } { \prg_return_true: } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_pass_features:} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_pass_features: { \prop_map_inline:Nn \g_@@_features_id_prop { \clist_if_empty:cF { l_@@_font_feat_##1_clist } { \clist_put_right:Nx \l_@@_fontspec_options_clist { ##2Features = { \exp_not:v { l_@@_font_feat_##1_clist } } } } } \prop_map_inline:Nn \l_@@_add_font_prop { \clist_put_right:Nn \l_@@_fontspec_options_clist { ##1 = {##2} } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal,var] % {\g_@@_family_name_prop,\g_@@_family_font_name_prop,\g_@@_family_font_options_prop} % \begin{macrocode} \prop_new:N \g_@@_family_name_prop \prop_new:N \g_@@_family_font_name_prop \prop_new:N \g_@@_family_font_options_prop % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_save_family_info:} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_save_family_info: { \group_begin: \prop_gput:NVV \g_@@_family_font_name_prop \l_@@_family_name_tl \l_@@_font_name_tl \prop_gput:NVV \g_@@_family_font_options_prop \l_@@_family_name_tl \l_@@_font_options_clist \group_end: } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_set_sub_block_family:} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_set_sub_block_family: { \prop_map_inline:Nn \l_@@_sub_key_prop { \tl_set:Nx \l_@@_sub_family_name_tl { \l_@@_family_name_tl/##1 } \quark_if_no_value:nTF {##2} { \@@_copy_sub_family:n {##1} } { \xeCJK_set_family:Voo \l_@@_sub_family_name_tl { \use_i:nn ##2 } { \use_ii:nn ##2 } } } } \cs_new_protected_nopar:Npn \@@_copy_sub_family:n #1 { \@@_check_family:V \l_@@_sub_family_name_tl \prop_get:NVNT \g_@@_family_font_name_prop \l_@@_family_name_tl \l_@@_sub_font_name_tl { \prop_gput:NVV \g_@@_family_font_name_prop \l_@@_sub_family_name_tl \l_@@_sub_font_name_tl } \prop_get:NVNT \g_@@_family_font_options_prop \l_@@_family_name_tl \l_@@_sub_font_options_clist { \clist_remove_all:Nn \l_@@_sub_font_options_clist { #1 = * } \prop_gput:NVV \g_@@_family_font_options_prop \l_@@_sub_family_name_tl \l_@@_sub_font_options_clist } \cs_gset_protected_nopar:cpx { \@@_family_csname:n { \l_@@_sub_family_name_tl } } { \xeCJK_family_if_exist:xT { \l_@@_family_name_tl } { \prop_get:NnNT \exp_not:N \g_@@_family_name_prop { \l_@@_family_name_tl } \exp_not:N \l_@@_fontspec_family_tl { \@@_gset_family_nfss_cs:xx { \l_@@_sub_family_name_tl } { \exp_not:N \l_@@_fontspec_family_tl } } } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_copy_family:nn} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_copy_family:nn #1#2 { \xeCJK_family_if_exist:xT {#2} { \tl_map_inline:nn { \g_@@_family_name_prop \g_@@_family_font_name_prop \g_@@_family_font_options_prop } { \prop_get:NnNT ##1 {#2} \l_@@_tmp_tl { \prop_gput:NnV ##1 {#1} \l_@@_tmp_tl } } \cs_gset_eq:cc { \@@_family_nfss_csname:n {#1} } { \@@_family_nfss_csname:n {#2} } } } \cs_generate_variant:Nn \@@_copy_family:nn { xx } % \end{macrocode} % \end{macro} % % \subsection{字体切换} % % \begin{macro}[internal]{\l_xeCJK_current_font_tl,\xeCJK_select_font:,\xeCJK_select_font:x} % 缓存当前字体的原始格式,以加速编译。 % \begin{macrocode} \tl_new:N \l_xeCJK_current_font_tl \tl_set:Nn \l_xeCJK_current_font_tl { \@@_font_csname:n { \l_xeCJK_family_tl } } \cs_new_nopar:Npn \@@_font_csname:n #1 { xeCJK/#1/\f@series/\f@shape/\f@size } \cs_new_protected_nopar:Npn \xeCJK_select_font: { \cs_if_exist_use:cF { \l_xeCJK_current_font_tl } { \tl_set:Nx \l_@@_current_coor_tl { \l_xeCJK_current_font_tl } \@@_family_use:x { \l_xeCJK_family_tl } \xeCJK_font_gset_to_current:c { \l_@@_current_coor_tl } } } \cs_new_protected_nopar:Npn \xeCJK_select_font:x #1 { \cs_if_exist_use:cF { \@@_font_csname:n {#1} } { \tl_set:Nx \l_@@_current_coor_tl { \@@_font_csname:n {#1} } \@@_family_use:x {#1} \xeCJK_font_gset_to_current:c { \l_@@_current_coor_tl } } } \tl_new:N \l_@@_current_coor_tl \cs_new_eq:NN \xeCJK@setfont \xeCJK_select_font: % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_switch_font:nn} % \changes{v3.1.0}{2012/11/18}{改进定义,加快切换速度。} % 两个 CJK 分区之间的字体切换。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_switch_font:nn #1#2 { \str_if_eq:nnF {#1} {#2} { \@@_info:nxx { CJK-block } {#1} {#2} \str_if_eq:nnTF {#2} { CJK } { \xeCJK_select_font: } { \@@_block_select_font:n {#2} } } } \@@_msg_new:nn { CJK-block } { Switch~from~block~`#1'~to~`#2'. } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_block_select_font:n} % 若当前 CJK 字体族没有定义子分区 |#1| 的字体,则使用 \cs{CJKfamilydefault} 的对应 % 分区字体;若 \cs{CJKfamilydefault} 也没有定义该分区字体,则使用当前 CJK 字体族的 % 主分区字体。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_block_select_font:n #1 { \cs_if_exist_use:cF { \@@_font_csname:n { \l_xeCJK_family_tl/#1 } } { \tl_set:Nx \l_@@_current_coor_tl { \@@_font_csname:n { \l_xeCJK_family_tl/#1 } } \xeCJK_family_if_exist:xF { \l_xeCJK_family_tl/#1 } { \@@_copy_family:xx { \l_xeCJK_family_tl/#1 } { \cs_if_exist:cTF { \@@_family_csname:n { \CJKfamilydefault/#1 } } { \CJKfamilydefault/#1 } { \l_xeCJK_family_tl } } } \@@_family_use:x { \l_xeCJK_family_tl/#1 } \xeCJK_font_gset_to_current:c { \l_@@_current_coor_tl } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal] % {\@@_family_csname:n,\@@_family_nfss_csname:n, % \@@_family_use:x,\@@_gset_family_nfss_cs:xx} % \begin{macrocode} \cs_new_nopar:Npn \@@_family_csname:n #1 { xeCJK/family/#1 } \cs_new_nopar:Npn \@@_family_nfss_csname:n #1 { xeCJK/family/nfss/#1 } \cs_new_nopar:Npn \@@_family_use:x #1 { \use:c { \@@_family_nfss_csname:n {#1} } } \cs_new_protected_nopar:Npn \@@_gset_family_nfss_cs:xx #1#2 { \prop_gput:Nxx \g_@@_family_name_prop {#1} {#2} \cs_gset_protected_nopar:cpx { \@@_family_nfss_csname:n {#1} } { \exp_not:N \fontencoding { \c_@@_encoding_tl } \tl_set:Nx \exp_not:N \f@family {#2} \exp_not:N \selectfont } } \cs_generate_variant:Nn \prop_gput:Nnn { Nxx } % \end{macrocode} % \end{macro} % % \begin{macro}[TF,internal]{\xeCJK_family_if_exist:x} % \begin{macrocode} \prg_new_protected_conditional:Npnn \xeCJK_family_if_exist:x #1 { T , F , TF } { \cs_if_exist:cTF { \@@_family_nfss_csname:n {#1} } { \use_i:nn } { \cs_if_exist_use:cTF { \@@_family_csname:n {#1} } } { \prg_return_true: } { \prg_return_false: } } % \end{macrocode} % \end{macro} % % \begin{macro}{\CJKfamily} % 用于切换 CJK 字体族。 % \begin{macrocode} \NewDocumentCommand \CJKfamily { t+ t- m } { \xeCJK_if_blank_x:nTF {#3} { \IfBooleanF {#1} { \IfBooleanF {#2} { \use_none:nn } } \xeCJK_family_if_exist_use:x { \l_xeCJK_family_tl } } { \IfBooleanTF {#2} { \xeCJK_family_if_exist_use:x {#3} } { \xeCJK_family_if_exist:xTF {#3} { \tl_set:Nx \l_xeCJK_family_tl {#3} \tl_set_eq:NN \xeCJK@family \l_xeCJK_family_tl \IfBooleanT {#1} { \@@_family_use:x {#3} } } { \@@_family_unknown_warning:x {#3} } } } \tex_ignorespaces:D } \cs_new_protected_nopar:Npn \xeCJK_switch_family:n #1 { \xeCJK_family_if_exist:xTF {#1} { \tl_set:Nx \l_xeCJK_family_tl {#1} \tl_set_eq:NN \xeCJK@family \l_xeCJK_family_tl } { \@@_family_unknown_warning:x {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}[var,internal]{\l_xeCJK_family_tl} % 用于保存文档当前正在使用的 CJK 字体族。 % \changes{v3.2.0}{2013/04/14}{不将其初始化为 \cs{CJKfamilydefault}。} % \begin{macrocode} \tl_new:N \l_xeCJK_family_tl % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_gobble_CJKfamily:} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_gobble_CJKfamily: { \cs_set_eq:NN \CJKfamily \@@_gobble_CJKfamily:wn } \DeclareExpandableDocumentCommand \@@_gobble_CJKfamily:wn { t+ t- m } { } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_family_if_exist_use:x} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_family_if_exist_use:x #1 { \xeCJK_family_if_exist:xTF {#1} { \@@_family_use:x {#1} } { \@@_family_unknown_warning:x {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_family_unknown_warning:n} % \changes{v3.1.2}{2013/01/01} % {在没有定义任何 CJK 字体的情况下,不再重复给出字体没有定义的警告。} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_family_unknown_warning:n #1 { \prop_if_empty:NF \g_@@_family_font_name_prop { \seq_if_in:NnF \g_@@_unknown_family_seq {#1} { \seq_gput_right:Nn \g_@@_unknown_family_seq {#1} \@@_warning:nx { CJKfamily-Unknown } {#1} } } } \cs_generate_variant:Nn \@@_family_unknown_warning:n { x } \seq_new:N \g_@@_unknown_family_seq \@@_msg_new:nn { CJKfamily-Unknown } { Unknown~CJK~family~`\@@_msg_family_map:n {#1}'~is~being~ignored.\\\\ Try~to~use~`\@@_msg_def_family_map:n {#1}'~to~define~it. } \cs_new_nopar:Npn \@@_msg_def_family_map:n #1 { \str_case_x:nnn {#1} { \CJKrmdefault { \token_to_str:N \setCJKmainfont } \CJKsfdefault { \token_to_str:N \setCJKsansfont } \CJKttdefault { \token_to_str:N \setCJKmonofont } } { \token_to_str:N \setCJKfamilyfont {#1} } [...]{...} } \cs_new_nopar:Npn \@@_msg_family_map:n #1 { \str_case_x:nnn {#1} { \CJKrmdefault { \token_to_str:N \CJKrmdefault } \CJKsfdefault { \token_to_str:N \CJKsfdefault } \CJKttdefault { \token_to_str:N \CJKttdefault } } {#1} } % \end{macrocode} % \end{macro} % % \begin{macro}{\setCJKmainfont,\setCJKsansfont,\setCJKmonofont} % 设置文档的 CJK 普通字体、无衬线和等宽字体。 % \changes{v3.2.0}{2013/04/14}{定义中加入 \cs{normalfont}。} % \begin{macrocode} \NewDocumentCommand \setCJKmainfont { O { } m } { \xeCJK_set_family:xxx { \CJKrmdefault } {#1} {#2} \normalfont } \cs_new_eq:NN \setCJKromanfont \setCJKmainfont \NewDocumentCommand \setCJKsansfont { O { } m } { \xeCJK_set_family:xxx { \CJKsfdefault } {#1} {#2} \normalfont } \NewDocumentCommand \setCJKmonofont { O { } m } { \xeCJK_set_family:xxx { \CJKttdefault } {#1} {#2} \normalfont } % \end{macrocode} % \end{macro} % % \begin{macrocode} \@onlypreamble \setCJKmainfont \@onlypreamble \setCJKmathfont \@onlypreamble \setCJKsansfont \@onlypreamble \setCJKmonofont \@onlypreamble \setCJKromanfont % \end{macrocode} % % \begin{macro}{\setCJKfamilyfont, \newCJKfontfamily, \CJKfontspec} % 分别用于预声明 CJK 字体和随机调用 CJK 字体。 % \begin{macrocode} \NewDocumentCommand \setCJKfamilyfont { m O { } m } { \xeCJK_set_family:xxx {#1} {#2} {#3} } \NewDocumentCommand \newCJKfontfamily { o m O { } m } { \tl_set:Nx \l_@@_tmp_tl { \IfNoValueTF {#1} { \cs_to_str:N #2 } {#1} } \cs_new_protected_nopar:Npx #2 { \xeCJK_switch_family:n { \l_@@_tmp_tl } } \xeCJK_set_family:xxx { \l_@@_tmp_tl } {#3} {#4} } \NewDocumentCommand \CJKfontspec { O { } m } { \use:x { \xeCJK_fontspec:nn {#1} {#2} } \tex_ignorespaces:D } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_fontspec:nn} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_fontspec:nn #1#2 { \prop_get:NnNTF \g_@@_fontspec_prop { CJKfontspec/#1/#2/id } \l_xeCJK_family_tl { \tl_set_eq:NN \xeCJK@family \l_xeCJK_family_tl } { \@@_fontspec:xnn { CJKfontspec ( \int_eval:n { \g_@@_family_int + \c_one } ) } {#1} {#2} } } \cs_new_protected_nopar:Npn \@@_fontspec:nnn #1#2#3 { \prop_gput:Nnn \g_@@_fontspec_prop { CJKfontspec/#2/#3/id } {#1} \xeCJK_set_family:nnn {#1} {#2} {#3} \xeCJK_switch_family:n {#1} } \cs_generate_variant:Nn \xeCJK_fontspec:nn { VV } \cs_generate_variant:Nn \@@_fontspec:nnn { x } \prop_new:N \g_@@_fontspec_prop % \end{macrocode} % \end{macro} % % \begin{macro}{\defaultCJKfontfeatures, \addCJKfontfeatures} % \changes{v3.2.4}{2013/06/30}{可以单独增加当前各个分区字体的属性。} % 分别用于设置 CJK 字体的默认属性和增加当前 CJK 字体的属性。 % \begin{macrocode} \clist_new:N \g_@@_default_features_clist \NewDocumentCommand \defaultCJKfontfeatures { m } { \clist_gset:Nn \g_@@_default_features_clist {#1} } \@onlypreamble \defaultCJKfontfeatures \NewDocumentCommand \addCJKfontfeatures { s O { } m } { \xeCJK_add_font_features:Nxx #1 {#2} {#3} \tex_ignorespaces:D } \cs_new_eq:NN \addCJKfontfeature \addCJKfontfeatures % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_add_font_features:Nnn} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_add_font_features:Nnn #1#2#3 { \prop_get:NVNTF \g_@@_family_font_name_prop \l_xeCJK_family_tl \l_@@_font_name_tl { \clist_set:Nn \l_@@_add_font_features_clist {#3} \seq_map_inline:Nn \g_@@_sub_key_seq { \clist_remove_all:Nn \l_@@_add_font_features_clist {##1} } \seq_clear:N \l_@@_sub_key_seq \clist_clear:N \l_@@_add_block_features_clist \clist_map_inline:nn {#2} { \seq_if_in:NnTF \g_@@_sub_key_seq {##1} { \seq_put_right:Nn \l_@@_sub_key_seq {##1} \@@_add_sub_class_features:n {##1} } { \@@_warning:nx { SubBlock-undefined } {##1} } } \bool_if:nT { #1 && \seq_if_empty_p:N \l_@@_sub_key_seq } { \seq_map_function:NN \g_@@_sub_key_seq \@@_add_sub_class_features:n } \prop_get:NVNT \g_@@_family_font_options_prop \l_xeCJK_family_tl \l_@@_font_options_clist { \bool_if:nT { \seq_if_empty_p:N \l_@@_sub_key_seq || #1 } { \clist_concat:NNN \l_@@_font_options_clist \l_@@_font_options_clist \l_@@_add_font_features_clist } \clist_concat:NNN \l_@@_font_options_clist \l_@@_font_options_clist \l_@@_add_block_features_clist } \xeCJK_fontspec:VV \l_@@_font_options_clist \l_@@_font_name_tl } { \@@_warning:n { addCJKfontfeature-ignored } } } \clist_new:N \l_@@_add_font_features_clist \clist_new:N \l_@@_add_block_features_clist \cs_generate_variant:Nn \xeCJK_add_font_features:Nnn { Nxx , Nnx } \@@_msg_new:nn { addCJKfontfeature-ignored } { \token_to_str:N \addCJKfontfeature (s)~ignored.\\\\ It~cannot~be~used~with~a~font~that~wasn't~selected~by~xeCJK. } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_add_sub_class_features:n} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_add_sub_class_features:n #1 { \prop_get:NoNTF \g_@@_family_font_name_prop { \l_xeCJK_family_tl/#1 } \l_@@_sub_font_name_tl { \prop_get:NoN \g_@@_family_font_options_prop { \l_xeCJK_family_tl/#1 } \l_@@_sub_font_options_clist } { \prop_get:NxNTF \g_@@_family_font_name_prop { \CJKfamilydefault/#1 } \l_@@_sub_font_name_tl { \prop_get:NxN \g_@@_family_font_options_prop { \CJKfamilydefault/#1 } \l_@@_sub_font_options_clist } { \prop_get:NVN \g_@@_family_font_options_prop \l_xeCJK_family_tl \l_@@_sub_font_options_clist \tl_set_eq:NN \l_@@_sub_font_name_tl \l_@@_font_name_tl } } \clist_concat:NNN \l_@@_sub_font_options_clist \l_@@_sub_font_options_clist \l_@@_add_font_features_clist \clist_put_right:Nx \l_@@_add_block_features_clist { #1 = { [ \exp_not:V \l_@@_sub_font_options_clist ] { \exp_not:V \l_@@_sub_font_name_tl } } } } \cs_generate_variant:Nn \prop_get:NnN { Nx } \cs_generate_variant:Nn \prop_get:NnNTF { Nx } % \end{macrocode} % \end{macro} % % \changes{v3.1.2}{2013/01/01}{修正重定义 \cs{CJKfamilydefault} 无效的问题,恢复容错能力。} % % 在导言区结束的时候,若没有声明 CJK 字体,则给出一个警告。如果 \cs{CJKfamilydefault} % 没有被更改,则在此时根据西文字体的情况更新 \cs{CJKfamilydefault}。 % 如果 \cs{CJKfamilydefault} 对应的字体族没有定义,则使用 \cs{CJKrmdefault} 作为 % 默认字体族。若 \cs{CJKrmdefault} 也没有定义,则使用在导言区设置的第一个 CJK 字体 % 作为默认字体族。最后设置数学字体。 % \begin{macrocode} \@@_at_end_preamble:n { \cs_set_eq:NN \@@_family_default_wrap:n \exp_not:n \tl_if_eq:NNT \CJKfamilydefault \l_@@_family_default_init_tl { \tl_gset:Nx \CJKfamilydefault { \str_case_x:nnn { \familydefault } { { \rmdefault } { \exp_not:N \CJKrmdefault } { \sfdefault } { \exp_not:N \CJKsfdefault } { \ttdefault } { \exp_not:N \CJKttdefault } } { \CJKfamilydefault } } } \cs_undefine:N \@@_family_default_wrap:n \prop_if_empty:NTF \g_@@_family_font_name_prop { \@@_warning:nx { no-CJKfamily } { \CJKfamilydefault } } { \xeCJK_family_if_exist:xF { \CJKfamilydefault } { \tl_set_eq:NN \l_@@_tmp_tl \CJKfamilydefault \str_if_eq_x:nnTF { \CJKfamilydefault } { \CJKrmdefault } { \use:n } { \xeCJK_family_if_exist:xTF { \CJKrmdefault } { \tl_gset:Nn \CJKfamilydefault { \CJKrmdefault } } } { \prop_map_inline:Nn \g_@@_family_font_name_prop { \prop_map_break:n { \tl_gset_rescan:Nnn \CJKfamilydefault { } {#1} } } } \@@_warning:nxx { CJKfamilydefault-undefined } { \l_@@_tmp_tl } { \CJKfamilydefault } } \xeCJK_switch_family:n { \CJKfamilydefault } \bool_if:NT \g_@@_math_bool { \xeCJK_set_mathfont: } } } \@@_msg_new:nn { no-CJKfamily } { It~seems~that~you~have~not~declare~a~CJKfamily.\\ If~you~want~to~use~xeCJK~in~the~right~way,~you~should~use\\\\ `\@@_msg_def_family_map:n {#1}'\\\\ in~the~preamble~to~declare~the~default~CJKfamily.\\ } \@@_msg_new:nn { CJKfamilydefault-undefined } { Undefined~CJK~default~family~`\@@_msg_family_map:n {#1}'~ has~been~replaced~by~`\@@_msg_family_map:n {#2}'.\\\\ Try~to~use~`\@@_msg_def_family_map:n {#1}'~to~define~it. } % \end{macrocode} % % \subsection{数学字体设置} % % \begin{macro}{CJKmath} % 是否启用 CJK 数学字体的宏包选项。 % \begin{macrocode} \keys_define:nn { xeCJK / options } { CJKmath .bool_gset:N = \g_@@_math_bool } % \end{macrocode} % \end{macro} % % \begin{macro}{\setCJKmathfont} % 设置 CJK 数学字体。 % \begin{macrocode} \NewDocumentCommand \setCJKmathfont { O { } m } { \xeCJK_set_family:xxx { \c_@@_math_tl } {#1} {#2} } \tl_const:Nn \c_@@_math_tl { CJKmath } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_set_mathfont:} % 当没有设置 CJK 数学字体时,使用 \cs{CJKfamilydefault} 作为数学字体。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_set_mathfont: { \xeCJK_family_if_exist:xTF { \c_@@_math_tl } { \tl_set:Nx \l_@@_tmp_tl { \c_@@_math_tl } } { \xeCJK_family_if_exist:xTF { \CJKfamilydefault } { \tl_set:Nx \l_@@_tmp_tl { \CJKfamilydefault } } { \use_none:nnnnn } } \prop_get:NVNT \g_@@_family_name_prop \l_@@_tmp_tl \l_@@_tmp_tl { \tl_const:Nx \c_@@_math_family_tl { \l_@@_tmp_tl } \DeclareSymbolFont \c_@@_math_tl \c_@@_encoding_tl \c_@@_math_family_tl \mddefault \shapedefault \SetSymbolFont \c_@@_math_tl { bold } \c_@@_encoding_tl \c_@@_math_family_tl \bfdefault \shapedefault \int_const:Nn \c_xeCJK_math_fam_int { \use:c { sym \c_@@_math_tl } } \clist_concat:NNN \l_@@_tmp_clist \c_@@_CJK_chars_clist \c_@@_FullLeft_chars_clist \clist_concat:NNN \l_@@_tmp_clist \l_@@_tmp_clist \c_@@_FullRight_chars_clist \clist_map_inline:Nn \l_@@_tmp_clist { \@@_set_char_class_aux:Nnw \xeCJK_gset_mathcode:nnnn {##1} { \c_seven } { \c_xeCJK_math_fam_int } } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_gset_mathcode:nnnn} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_gset_mathcode:nnnn #1#2#3#4 { \@@_check_num_range:nnNN {#1} {#2} \l_@@_begin_int \l_@@_end_int \xeCJK_int_until_do:nn { \l_@@_begin_int > \l_@@_end_int } { \tex_global:D \xeCJK_xetex_mathcode:w \l_@@_begin_int = #3 ~ #4 \l_@@_begin_int \int_incr:N \l_@@_begin_int } } % \end{macrocode} % \end{macro} % % % \subsection{抄录环境中的间距调整} % % \changes{v3.1.0}{2012/11/19}{放弃使用放缩字体大小的方式,而只采用调整间距的方式 % 与西文等宽字体对齐。并且只适用于与抄录环境下。} % \changes{v3.2.0}{2013/04/15}{增加 \texttt{Verb} 选项。} % \changes{v3.2.1}{2013/05/29}{调整 \texttt{Verb} 选项:在命令 \cs{verb} 里使用时, % 不破坏标点禁则,增加值 \texttt{env+}。} % % \begin{macro}{Verb} % \changes{v3.2.5}{2013/07/25}{微调定义。} % 如果设置为 \texttt{env},则只在 \LaTeX 的抄录环境里使用 \cs{xeCJKVerbAddon},^^A % 而不包括 \cs{verb}。对当前使用环境的判断基于在标准 \LaTeX 的坏境定义里使用 % \cs{begingroup} 和 \cs{endgroup} 来分组。 % \begin{macrocode} \int_new:N \l_@@_verb_case_int \keys_define:nn { xeCJK / options } { Verb .choices:nn = { true , env , env+ , false } { \int_set_eq:NN \l_@@_verb_case_int \l_keys_choice_int } , Verb .default:n = { env } } \cs_new_protected_nopar:Npn \@@_verb_font_hook: { \if_case:w \l_@@_verb_case_int \or: \cs_set_eq:NN \CJKglue \@@_zero_glue: \cs_set_eq:NN \CJKecglue \@@_zero_glue: \or: \int_compare:nNnTF \etex_currentgrouptype:D = \c_fourteen { \xeCJKVerbAddon } { \cs_set_eq:NN \CJKglue \@@_zero_glue: \cs_set_eq:NN \CJKecglue \@@_zero_glue: } \or: \int_compare:nNnT \etex_currentgrouptype:D = \c_fourteen { \xeCJKVerbAddon } \fi: } \@@_after_preamble:n { \cs_set_protected_nopar:Npx \verbatim@font { \exp_not:o { \verbatim@font } \@@_verb_font_hook: } } % \end{macrocode} % \end{macro} % % \begin{macro}{\xeCJKOffVerbAddon,\xeCJKVerbAddon} % \changes{v3.1.0}{2012/11/19}{新增 \cs{xeCJKVerbAddon} 用于抄录环境中的间距调整。} % \changes{v3.2.3}{2013/06/04} % {新增 \cs{xeCJKOffVerbAddon} 用于局部取消 \cs{xeCJKOffVerbAddon} 的影响;并解决 % 跨页使用时影响到页眉页脚的问题。} % \changes{v3.2.5}{2013/07/13}{禁止自动换行,与西文一致。} % \cs{xeCJKVerbAddon} 进行了比较大的调整,应该只在分组环境里使用。为了方便调整间距 % 以利于对齐,这里只把字符分成了两类,并且在 CJK 类与边界(空格)之间也插入 % \cs{CJKecglue}。当然,这样做之后,关于标点符号的禁则就没有了。 % \begin{macrocode} \NewDocumentCommand \xeCJKVerbAddon { } { \int_compare:nNnF \etex_currentgrouplevel:D = \c_zero { \bool_if:NF \l_@@_listings_env_bool { \@@_set_verb_exspace: \@@_verb_addon: } } } \bool_new:N \l_@@_listings_env_bool \NewDocumentCommand \xeCJKOffVerbAddon { } { } \cs_new_protected_nopar:Npn \@@_verb_addon: { \bool_if:NF \l_@@_verb_addon_bool { \bool_set_true:N \l_@@_verb_addon_bool \@@_set_char_class_eq:nn { FullLeft } { CJK } \@@_set_char_class_eq:nn { FullRight } { CJK } \@@_set_char_class_eq:nn { HalfLeft } { Default } \@@_set_char_class_eq:nn { HalfRight } { Default } \@@_set_char_class_eq:nn { NormalSpace } { Default } \cs_set_eq:NN \@@_verb_CJKglue: \CJKglue \cs_set_eq:NN \@@_verb_CJKecglue: \CJKecglue \cs_set_eq:NN \@@_verb_check_for_glue: \xeCJK_check_for_glue: \cs_set_eq:NN \@@_verb_ignore_spaces:w \xeCJK_ignore_spaces:w \cs_set_protected_nopar:Npx \xeCJKOffVerbAddon { \@@_reset_char_class:n { FullLeft } \@@_reset_char_class:n { FullRight } \@@_reset_char_class:n { HalfLeft } \@@_reset_char_class:n { HalfLeft } \@@_reset_char_class:n { NormalSpace } \exp_not:c { bool_set_ \bool_if:NTF \l_@@_xecglue_bool { true } { false } :N } \l_@@_xecglue_bool \exp_not:n { \cs_set_eq:NN \CJKglue \@@_verb_CJKglue: \cs_set_eq:NN \CJKecglue \@@_verb_CJKecglue: \cs_set_eq:NN \xeCJK_check_for_glue: \@@_verb_check_for_glue: \cs_set_eq:NN \xeCJK_ignore_spaces:w \@@_verb_ignore_spaces:w } } \tex_output:D \exp_after:wN \exp_after:wN \exp_after:wN { \exp_after:wN \exp_after:wN \exp_after:wN \xeCJKOffVerbAddon \exp_after:wN \use:n \tex_the:D \tex_output:D } \xeCJKsetup { xCJKecglue = false } } \skip_if_eq:nnTF { \l_@@_verb_exspace_skip } { \c_zero_skip } { \xeCJK_cs_clear:N \CJKglue \xeCJK_cs_clear:N \CJKecglue } { \cs_set_eq:NN \CJKglue \@@_verb_ccglue: \cs_set_eq:NN \CJKecglue \@@_verb_ecglue: } \cs_set_eq:NN \xeCJK_check_for_glue: \CJKecglue \cs_set_eq:NN \xeCJK_ignore_spaces:w \CJKecglue } \cs_new_protected_nopar:Npn \@@_verb_ccglue: { \xeCJK_no_break: \skip_horizontal:N \l_@@_verb_exspace_skip } \cs_new_protected_nopar:Npn \@@_verb_ecglue: { \xeCJK_no_break: \skip_horizontal:n { 0.5 \l_@@_verb_exspace_skip } } \cs_new_protected_nopar:Npn \@@_reset_char_class:n #1 { \int_set:Nn \l_@@_tmp_int { \xeCJK_class_num:n {#1} } \clist_map_inline:cn { c_@@_#1_chars_clist } { \XeTeXcharclass ##1 = \l_@@_tmp_int } } \bool_new:N \l_@@_verb_addon_bool \cs_new_eq:NN \CJKfixedspacing \xeCJKVerbAddon % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_set_verb_exspace:} % \changes{v3.1.1}{2012/12/08}{调整间距的计算方法。} % \changes{v3.2.4}{2013/06/29}{当计算得出的间距为负时,缩小 CJK 字体。} % 在抄录环境中,CJK 文字之间的间距为当前西文字体两个空格的宽度与当前字体大小之差, % 而与西文和空格的间距为 CJK 文字之间的间距的一半。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_set_verb_exspace: { \tl_if_exist:cTF { xeCJK/verb/\l_xeCJK_family_tl/\curr@fontshape/\f@size } { \skip_set:Nn \l_@@_verb_exspace_skip { \use:c { xeCJK/verb/\l_xeCJK_family_tl/\curr@fontshape/\f@size } } } { \tl_set:Nx \l_@@_current_coor_tl { \l_xeCJK_family_tl/\curr@fontshape } \prop_get:NVNTF \g_@@_scale_family_prop \l_@@_current_coor_tl \l_xeCJK_family_tl { \tl_set_eq:NN \xeCJK@family \l_xeCJK_family_tl \skip_zero:N \l_@@_verb_exspace_skip } { \group_begin: \xeCJK_select_font: \exp_after:wN \group_end: \exp_after:wN \@@_set_verb_exspace:n \exp_after:wN { \dim_use:N \etex_fontcharwd:D \tex_font:D "4E00 } } } } \skip_new:N \l_@@_verb_exspace_skip % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_set_verb_exspace:n} % 当两个西文空格的宽度小于一个 CJK 文字的宽度时,对目前使用的 CJK 字体进行适当缩小。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_set_verb_exspace:n #1 { \skip_set:Nn \l_@@_verb_exspace_skip { \c_two \tex_fontdimen:D \c_two \tex_font:D - #1 } \dim_compare:nNnTF \l_@@_verb_exspace_skip < \c_zero_dim { \skip_zero:N \l_@@_verb_exspace_skip \use:x { \@@_set_verb_scale:nn { \dim_to_fp:n { \c_two \tex_fontdimen:D \c_two \tex_font:D } } { \dim_to_fp:n {#1} } } } { \tl_const:cx { xeCJK/verb/\l_xeCJK_family_tl/\curr@fontshape/\f@size } { \skip_use:N \l_@@_verb_exspace_skip } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_set_verb_scale:nn} % 缩小 CJK 字体,并保存相关信息。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_set_verb_scale:nn #1#2 { \fp_set:Nn \l_@@_scale_factor_fp { #1 / #2 } \@@_warning:nxx { scale-factor } { \fp_eval:n { round - ( \l_@@_scale_factor_fp , 4 ) } } { \fp_eval:n { round + ( #2 / #1 , 4 ) } } \xeCJK_add_font_features:Nnx \c_true_bool { } { Scale = { \fp_use:N \l_@@_scale_factor_fp } } \prop_gput:NVV \g_@@_scale_family_prop \l_@@_current_coor_tl \l_xeCJK_family_tl } \@@_msg_new:nn { scale-factor } { `\token_to_str:N \xeCJKVerbAddon'~may~not~work~properly.\\\\ You~may~set~`Scale=#1'~to~CJKfamily~ `\@@_msg_family_map:n { \l_xeCJK_family_tl }',\\ or~set~`Scale=#2'~to~family~ `\str_if_eq_x:nnTF \f@family \ttdefault { \token_to_str:N \ttdefault } { \f@family }'. } \fp_new:N \l_@@_scale_factor_fp \prop_new:N \g_@@_scale_family_prop % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_visible_space:} % \changes{v3.2.5}{2013/07/13}{可视空格考虑传统 \TeX 字体的情况。} % 如果文档不使用 \texttt{EU1} 作为默认字体编码,那么默认的打字机字体族很可能是 % 传统的 \TeX 字体,这时可视空格按照 \texttt{OT1} 编码传统一般就是字体中的 |\char32|。 % 这里加入 \cs{scan_stop:} 的目的是强制发生状态转移。这样当空格出现在 CJK 文字 % 后面时,使字体回到西文,保证在当前西文字体而不是在 CJK 字体中检查有没有 |U+2423|。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_visible_space: { \bool_if:NT \l_@@_CJK_group_bool { \scan_stop: } \xeCJK_glyph_if_exist:NTF { ^^^^2423 } { ^^^^2423 } { \int_compare:nNnTF { \XeTeXfonttype \tex_font:D } = \c_zero { \str_if_eq_x:nnTF { \f@family } { \ttdefault } { \c_catcode_other_space_tl } { \textvisiblespace } } { \xeCJK_visible_space_fallback: } } } \AtEndOfPackage { \cs_gset_eq:NN \fontspec_visible_space: \xeCJK_visible_space: } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_visible_space_fallback:} % \changes{v3.1.0}{2012/11/19} % {调整 \pkg{fontspec} 的后备可视空格符号,以便于使用时对齐。} % \pkg{fontspec} 使用 |lmtt| 字体中的可视空格符号(|U+2423|)作为当前字体中相应符号 % 的后备。但是 |lmtt| 的字体大小未必与当前字体匹配。因此,我们在这里做一些调整,以 % 保证使用后备可视空格符号时,也能保证对齐。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_visible_space_fallback: { { \cs_if_exist_use:cF { xeCJK/space/\curr@fontshape/\f@size } { \xeCJK_set_visible_space_font: } ^^^^2423 } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK_set_visible_space_font:} % 当前字体空格的宽度与后备字体 |lmtt| 不一样时,就对 \cs{textvisiblespace} 的字体尺寸 % 按相应的比例放缩。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_set_visible_space_font: { \tl_set:Nx \l_@@_current_coor_tl { xeCJK/space/\curr@fontshape/\f@size } \exp_after:wN \@@_set_visible_space_size:n \exp_after:wN { \dim_use:N \tex_fontdimen:D \c_two \tex_font:D } \xeCJK_font_gset_to_current:c { \l_@@_current_coor_tl } } \cs_new_protected_nopar:Npn \@@_set_visible_space_size:n #1 { \fontencoding { \g_fontspec_encoding_tl } \tl_set:Nx \f@family { lmtt } \selectfont \dim_compare:nNnF {#1} = { \tex_fontdimen:D \c_two \tex_font:D } { \fontsize { \dim_eval:n { \f@size pt * \dim_ratio:nn {#1} { \tex_fontdimen:D \c_two \tex_font:D } } } { \f@baselineskip } \selectfont } } % \end{macrocode} % \end{macro} % % \subsection{\pkg{xeCJK} 其它选项} % % \begin{macro}{LocalConfig} % \changes{v3.1.0}{2012/11/20}{增加 \texttt{LocalConfig} 选项用于载入本地配置文件。} % 声明载入本地配置文件的选项。 % \begin{macrocode} \keys_define:nn { xeCJK / options } { LocalConfig .choice: , LocalConfig / false .code:n = { \bool_gset_false:N \g_@@_config_bool } , LocalConfig / true .code:n = { \bool_gset_true:N \g_@@_config_bool \tl_gset:Nn \g_@@_config_name_tl { xeCJK } } , LocalConfig / unknown .code:n = { \bool_gset_true:N \g_@@_config_bool \tl_gset:Nx \g_@@_config_name_tl { xeCJK - \l_keys_value_tl } } , LocalConfig .default:n = { true } } \tl_new:N \g_@@_config_name_tl \bool_new:N \g_@@_config_bool % \end{macrocode} % \end{macro} % % \begin{macro}{indentfirst} % 首行是否缩进。 % \begin{macrocode} \keys_define:nn { xeCJK / options } { CJKnumber .bool_gset:N = \g_@@_number_bool , indentfirst .bool_gset:N = \g_@@_indent_bool , normalindentfirst .meta:n = { indentfirst = false } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{quiet,silent} % 将调用 \pkg{xeCJK} 时使用的未知的选项传递给 \pkg{fontspec} 宏包。 % 对 \pkg{fontspec} 的 |quiet| 和 |silent| 选项进行修改,使其适用于 \pkg{xeCJK}。 % \begin{macrocode} \keys_define:nn { xeCJK / options } { quiet .code:n = { \msg_redirect_module:nnn { xeCJK } { warning } { info } \msg_redirect_module:nnn { xeCJK } { info } { none } \xeCJK_if_package_loaded:nF { fontspec } { \PassOptionsToPackage { quiet } { fontspec } } } , silent .code:n = { \msg_redirect_module:nnn { xeCJK } { warning } { none } \msg_redirect_module:nnn { xeCJK } { info } { none } \xeCJK_if_package_loaded:nF { fontspec } { \PassOptionsToPackage { silent } { fontspec } } } , unknown .code:n = { \xeCJK_if_package_loaded:nTF { fontspec } { \@@_error:nx { key-unknown } { \l_keys_key_tl } } { \PassOptionsToPackage { \l_keys_key_tl } { fontspec } } } } \@@_msg_new:nn { key-unknown } { Sorry,~but~\l__keys_module_tl \ does~not~have~a~key~called~`#1'.\\\\ The~key~`#1'~is~being~ignored. } % \end{macrocode} % \end{macro} % % \subsection{\pkg{xeCJK} 初始化设置} % % \begin{macro}[internal]{\CJKsymbol, \CJKpunctsymbol} % \begin{macrocode} \cs_new_nopar:Npn \CJKsymbol #1 {#1} \cs_new_nopar:Npn \CJKpunctsymbol #1 {#1} % \end{macrocode} % \end{macro} % % \pkg{xeCJK} 宏包的初始化设置。 % % \begin{macrocode} \keys_set:nn { xeCJK / options } { CJKglue = { \skip_horizontal:n { \c_zero_dim plus 0.08 \tex_baselineskip:D } } , CJKecglue = { ~ } , xCJKecglue = false , CheckSingle = false , PlainEquation = false , CheckFullRight = false , CJKspace = false , CJKmath = false , CJKnumber = false , xeCJKactive = true , LocalConfig = true , indentfirst = true , Verb = env , EmboldenFactor = 4 , SlantFactor = 0.167 , PunctStyle = quanjiao , NewLineCS = { \par \[ } , EnvCS = { \begin \end } , NoBreakCS = { \footnote \footnotemark \nobreak } , KaiMingPunct = { ^^^^3002 ^^^^ff0e ^^^^ff1f ^^^^ff01 } , LongPunct = { ^^^^2014 ^^^^2015 ^^^^2500 ^^^^2025 ^^^^2026 } , MiddlePunct = { ^^^^2014 ^^^^2015 ^^^^2027 ^^^^2500 ^^^^00b7 ^^^^30fb ^^^^ff65 } , AllowBreakBetweenPuncts = false } \defaultCJKfontfeatures { Script = CJK } % \end{macrocode} % % 执行宏包选项,并载入 \pkg{fontspec} 宏包和 \pkg{xunicode-addon}。 % \begin{macrocode} \ProcessKeysOptions { xeCJK / options } \RequirePackage { fontspec } [ 2011/09/13 ] \RequirePackage { xunicode-addon } % \end{macrocode} % % \begin{macro}[internal,var]{\c_@@_encoding_tl} % 保存 \pkg{fontspec} 声明字体时使用的字体编码。 % \begin{macrocode} \tl_const:Nx \c_@@_encoding_tl { \g_fontspec_encoding_tl } % \end{macrocode} % \end{macro} % % 章节标题后面的首个段落的首行是否缩进。 % \changes{v3.1.0}{2012/11/21}{改用 \pkg{indentfirst} 宏包处理缩进的问题。} % \begin{macrocode} \bool_if:NT \g_@@_indent_bool { \RequirePackage { indentfirst } } % \end{macrocode} % % 对不能通过 \cs{xeCJKsetup} 设置的选项给出警告。 % \begin{macrocode} \keys_define:nn { xeCJK / options } { LocalConfig .code:n = { \@@_warning:nx { option-invalid } { \l_keys_key_tl } } , CJKnumber .code:n = { \@@_warning:nx { option-invalid } { \l_keys_key_tl } } , indentfirst .code:n = { \@@_warning:nx { option-invalid } { \l_keys_key_tl } } } \@@_msg_new:nn { option-invalid } { The~`#1'~option~only~can~be~set~in~the~optional~argument~to~the\\ \token_to_str:N \usepackage \ command~when~xeCJK~is~being~loaded.\\\\ Please~do~not~set~it~via~the~\token_to_str:N \xeCJKsetup \ command. } % \end{macrocode} % % \begin{macro}[var]{\CJKrmdefault,\CJKsfdefault,\CJKttdefault,\CJKfamilydefault} % \begin{macrocode} \tl_if_exist:NF \CJKrmdefault { \tl_gset:Nn \CJKrmdefault { rm } } \tl_if_exist:NF \CJKsfdefault { \tl_gset:Nn \CJKsfdefault { sf } } \tl_if_exist:NF \CJKttdefault { \tl_gset:Nn \CJKttdefault { tt } } \tl_new:N \l_@@_family_default_init_tl \cs_new_eq:NN \@@_family_default_wrap:n \use:n \tl_set:Nx \l_@@_family_default_init_tl { \exp_not:N \@@_family_default_wrap:n { \tl_if_exist:NTF \CJKfamilydefault { \exp_not:V \CJKfamilydefault } { \exp_not:N \CJKrmdefault } } } \tl_gset_eq:NN \CJKfamilydefault \l_@@_family_default_init_tl % \end{macrocode} % \end{macro} % % \begin{macro}{\xeCJKsetup} % 在导言区或文档中设置 \pkg{xeCJK} 的接口。 % \begin{macrocode} \NewDocumentCommand \xeCJKsetup { +m } { \keys_set:nn { xeCJK / options } {#1} \tex_ignorespaces:D } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJKsetemboldenfactor, \xeCJKsetslantfactor} % \begin{macrocode} \NewDocumentCommand \xeCJKsetemboldenfactor { m } { \xeCJKsetup { EmboldenFactor = {#1} } } \NewDocumentCommand \xeCJKsetslantfactor { m } { \xeCJKsetup { SlantFactor = {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\punctstyle, \xeCJKplainchr} % \begin{macrocode} \NewDocumentCommand \punctstyle { m } { \xeCJKsetup { PunctStyle = {#1} } } \NewDocumentCommand \xeCJKplainchr { } { \xeCJKsetup { PunctStyle = plain } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\CJKsetecglue} % \begin{macrocode} \NewDocumentCommand \CJKsetecglue { m } { \xeCJKsetup { CJKecglue = {#1} } } \cs_new_eq:NN \xeCJKsetecglue \CJKsetecglue % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\CJKspace,\CJKnospace} % \begin{macrocode} \NewDocumentCommand \CJKspace { } { \xeCJKsetup { CJKspace = true } } \NewDocumentCommand \CJKnospace { } { \xeCJKsetup { CJKspace = false } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJKallowbreakbetweenpuncts, \xeCJKnobreakbetweenpuncts} % \begin{macrocode} \NewDocumentCommand \xeCJKallowbreakbetweenpuncts { } { \xeCJKsetup { AllowBreakBetweenPuncts = true } } \NewDocumentCommand \xeCJKnobreakbetweenpuncts { } { \xeCJKsetup { AllowBreakBetweenPuncts = false } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJKenablefallback, \xeCJKdisablefallback} % \begin{macrocode} \NewDocumentCommand \xeCJKenablefallback { } { \xeCJKsetup { AutoFallBack = true } } \NewDocumentCommand \xeCJKdisablefallback { } { \xeCJKsetup { AutoFallBack = false } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJKsetcharclass} % \begin{macrocode} \NewDocumentCommand \xeCJKsetcharclass { m m m } { \xeCJK_set_char_class:nnn {#1} {#2} {#3} \xeCJKResetPunctClass } % \end{macrocode} % \end{macro} % % \subsection{兼容性修补} % % \begin{macro}[internal]{\(} % \changes{v3.2.5}{2013/07/25} % {解决汉字后紧跟 \cs{(}\texttt{...}\cs{)} 形式的行内数学公式时,不能加入间距的问题。} % \cs{(} 的在 \LaTeXe 中的定义是 % \begin{verbatim} % \def\({\relax\ifmmode\@badmath\else$\fi} % \end{verbatim} % 这个定义最开始的 \cs{relax} 是为了防止 \cs{(} 出现在表格单元格的开始位置时,模式 % 判断不正确(因为 \TeX 会先看单元格中第一个不可展的非空格记号是否是 \cs{omit} 或 \cs{noalign})。^^A % 但是它会造成一个边界,使 \pkg{xeCJK} 不能看到 \cs{relax} 后面出现的 |$|,从而不能 % 加入间距\footnote{\url{http://tex.stackexchange.com/q/124773}}。使用 \hologo{eTeX} % 的 \cs{protected} 来定义它,可以不需要 \cs{relax},或者将 \cs{relax} 改成 % \cs{scan_align_safe_stop:},都可以避免这些情况。同时 \pkg{fixltx2e}中还使用了 % |\MakeRobust\(|,我们需要小心处理。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_math_robust:N #1 { \exp_args:NNc \@@_math_robust:NN #1 { \cs_to_str:N #1 ~ } } \cs_new_protected_nopar:Npn \@@_math_robust:NN #1#2 { \bool_if:nT { \str_if_eq_x_p:nn { \token_get_replacement_spec:N #1 } { \exp_not:n { \x@protect #1 \protect #2 } } && \exp_args:Nf \tl_if_empty_p:n { \token_get_arg_spec:N #2 } && \exp_args:No \tl_if_head_eq_meaning_p:nN {#2} \scan_stop: } { \cs_gset_protected_nopar:Npx #1 { \scan_align_safe_stop: \tl_tail:N #2 } } } \@@_math_robust:N \( \@@_math_robust:N \) % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\[} % \changes{v3.2.5}{2013/07/25}{解决 \pkg{fixltx2e} 和 \pkg{amsthm} 的冲突。} % 当 \pkg{amsmath} 没有在 \pkg{amsthm} 之前被调用时,\pkg{amsthm} 会展开 \cs{[}, % 并用 |$| 作为参数定界记号,相关代码为 % \begin{verbatim} % \def\@tempa#1$#2#3\@nil{% % \def\[{#1$#2\def\@currenvir{displaymath}#3}% % }% % \expandafter\@tempa\[\@nil % \end{verbatim} % 而 \pkg{fixltx2e} 中使用了 |\MakeRobust\[|,使得将 \cs{[} 展开一次的内容中并 % 不直接含有 |$|,从而造成了 \texttt{Runaway argument?} 的错误。可以在 \pkg{amsthm} % 之前引入 \pkg{amsmath},避免出现这个错误。我们下面用 \hologo{eTeX} 的 \cs{protected} % 来定义它。当然,如果之后只使用 \pkg{amsthm},那么 \cs{[} 会被修改,将不再是^^A % “健壮”的了。这也是上面 \cs{@@_math_robust:NN} 中还使用 \cs{scan_align_safe_stop:} 的原因。 % \begin{macrocode} \bool_if:nF { \xeCJK_if_package_loaded_p:n { amsmath } || \xeCJK_if_package_loaded_p:n { amsthm } } { \@@_math_robust:N \[ \@@_math_robust:N \] } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\nobreakspace} % \changes{v3.1.2}{2013/01/01} % {修正非 \cs{UTFencname} 编码下面 \pkg{xunicode} 重定义的 \cs{nobreakspace} 会失效的问题。} % \changes{v3.2.5}{2013/07/18}{恢复 \cs{nobreakspace} 的原始定义。} % 空格在 \TeX 中是特殊的记号,似乎不应该把它定义为字体中的符号(\texttt{U+00A0})。 % \begin{macrocode} \UndeclareTextCommand \nobreakspace { \UTFencname } \RenewDocumentCommand \nobreakspace { } { \leavevmode \nobreak \ } % \end{macrocode} % \end{macro} % % 当符号命令紧跟在 CJK 字符类后面时,强制发生状态转移,使字体回到西文状态。 % \begin{macrocode} \AtBeginUTFCommand { \bool_if:NT \l_@@_CJK_group_bool { \scan_stop: } } % \end{macrocode} % % \changes{v3.1.1}{2012/12/13}{对于与 \pkg{xltxtra} 的冲突给出错误警告。} % 比较老版本的 \pkg{realscripts} 定义了 \cs{dim_max:nn} 和 \cs{dim_min:nn},这与 % 新版本的 \pkg{expl3} 冲突。 % \begin{macrocode} \@@_msg_new:nn { conflict-package } { The~`#1'~package~is~too~old. \\ Please~update~an~up~to~date~version~of~it\\ using~your~TeX~package~manager~or~from~CTAN. } \xeCJK_if_package_loaded:nTF { realscripts } { \@ifpackagelater { realscripts } { 2010/10/10 } { } { \@@_error:nx { conflict-package } { \xeCJK_if_package_loaded:nTF { xltxtra } { xltxtra } { realscripts } } } } { \cs_new_eq:NN \@@_dim_max:nn \dim_max:nn \cs_new_eq:NN \@@_dim_min:nn \dim_min:nn \@@_at_end_preamble:n { \xeCJK_if_package_loaded:nT { realscripts } { \@ifpackagelater { realscripts } { 2010/10/10 } { } { \cs_gset_eq:NN \dim_max:nn \@@_dim_max:nn \cs_gset_eq:NN \dim_min:nn \@@_dim_min:nn } } \cs_undefine:N \@@_dim_max:nn \cs_undefine:N \@@_dim_min:nn } } % \end{macrocode} % % \begin{macro}[internal]{\fontfamily} % \changes{v3.1.1}{2012/12/06}{修改主要 \texttt{CJK} 字体族的自动更新方式。} % \changes{v3.1.2}{2013/01/01}{不将参数完全展开。} % 修改 \cs{fontfamily},使主要 |CJK| 字体族能随西文主要字体更新。 % \begin{macrocode} \RenewDocumentCommand \fontfamily { m } { \tl_set:Nx \f@family {#1} \@@_update_family:n { \str_case:nnn {#1} { { \rmdefault } { \xeCJK_switch_family:n { \CJKrmdefault } } { \sfdefault } { \xeCJK_switch_family:n { \CJKsfdefault } } { \ttdefault } { \xeCJK_switch_family:n { \CJKttdefault } } { \familydefault } { \xeCJK_switch_family:n { \CJKfamilydefault } } } { } } } \cs_new_eq:NN \@@_update_family:n \use:n % \end{macrocode} % \end{macro} % % \newbox\xeCJKtmpbox % \setbox\xeCJKtmpbox\vbox\bgroup\gobblelineno % \begin{macrocode} %<@@=> % \end{macrocode}\egroup % % \begin{macro}[internal]{\xeCJK@fix@penalty} % \changes{v3.1.0}{2012/11/13}{采用通过不修改原语 \cs{/} 的方式对修复倾斜校正。} % 对 \LaTeXe 内核中的 \cs{fix@penalty} 被用于诸如 \cs{textit} 之类的文档 % 字体转换命令的定义之中。这里对它进行补丁的目的是修复其中的倾斜校正,并使得这些 % 文档命令与紧随其后的汉字之间可以正确的插入 \cs{CJKecglue} 或者忽略其中的空格。 % 例如 \verb*|这是 \emph{强调} 文本|,第二个空格可以被忽略掉。如果使用 |xCJKecglue| % 选项,第一个空格也可以被省略。事实上,在 \cs{sw@slant} 的定义中,\cs{@@italiccorr} % 前面的 \cs{lastskip} 和 \cs{lastpenalty} 有四种情况,这里只对它们都为零的情况进行 % 处理。 % \begin{macrocode} \cs_new_eq:NN \xeCJK@fix@penalty \fix@penalty \tl_replace_once:Nnn \xeCJK@fix@penalty { \@@italiccorr } { \xeCJK@italiccorr } \tl_replace_once:Nnn \sw@slant { \fix@penalty } { \xeCJK@fix@penalty } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\xeCJK@italiccorr} % 修复倾斜校正,并处理汉字后面的空格。 % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK@italiccorr { \int_compare:nNnTF \XeTeXinterchartokenstate > \c_zero { \xeCJK_if_last_node:nTF { default } { \xeCJK_remove_node: \@@italiccorr { \xeCJK_make_node:n { default } } } { \xeCJK_if_last_node:nTF { CJK } { \xeCJK_remove_node: \@@italiccorr { \xeCJK_make_node:n { CJK } } \use:n } { \xeCJK_if_last_node:nTF { CJK-space } { \xeCJK_remove_node: \@@italiccorr { \xeCJK_make_node:n { CJK-space } } \use:n } { \@@italiccorr \use_none:n } } % \end{macrocode} % \cs{xeCJK_ignore_spaces:w} 里面用到 |peek| 函数来判断后面是不是空格,而此时它 % 后面还有 $4$ 个 \cs{fi} 或者 |\else...\fi| 没有被展开,将影响 |peek| 函数的 % 判断。因此我们需要用 $2^4-1=15$ 个 \cs{exp_after:wN} 来展开它们。 % 显然,这里用 \cs{exp_last_unbraced:Nf} 会比较方便,但是它会吃掉 % \verb*|\textit{...} | 等后面原来存在的空格作为完全展开的结束。要正确使用它还 % 需要另外的处理(使用 \cs{exp_stop_f:})。 % \begin{macrocode} { \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN \xeCJK_ignore_spaces:w } } } { \@@italiccorr } } % \end{macrocode} % \end{macro} % % \setbox\xeCJKtmpbox\vbox\bgroup\gobblelineno % \begin{macrocode} %<@@=xeCJK> % \end{macrocode}\egroup % % \begin{macro}[internal]{\@@_set_others_toks:n} % 简单处理与同样使用 \cs{XeTeXinterchartoks} 机制的宏包的兼容问题。 % \begin{macrocode} \@@_after_end_preamble:n { \int_compare:nNnF { \c_three + \seq_count:N \g_@@_new_class_seq } = \xe@alloc@intercharclass { \int_step_inline:nnnn \c_four \c_one \xe@alloc@intercharclass { \seq_if_in:NnF \g_@@_new_class_seq {#1} { \@@_set_others_toks:n {#1} } } } } \cs_new_protected_nopar:Npn \@@_set_others_toks:n #1 { \int_set:cn { \@@_class_csname:n { Others } } {#1} \seq_map_inline:Nn \g_@@_CJK_class_seq { \xeCJK_copy_inter_class_toks:nnnn {##1} { Others } {##1} { NormalSpace } \xeCJK_copy_inter_class_toks:nnnn { Others } {##1} { NormalSpace } {##1} \xeCJK_app_inter_class_toks:nnx {##1} { Others } { \xeCJK_get_inter_class_toks:nn { Default } { Others } } \xeCJK_pre_inter_class_toks:nnx { Others } {##1} { \xeCJK_get_inter_class_toks:nn { Others } { Default } } \xeCJK_if_blank_x:nT { \xeCJK_get_inter_class_toks:nn { Others } { Boundary } } { \xeCJK_copy_inter_class_toks:nnnn { Others } { Boundary } { Default } { Boundary } } \xeCJK_if_blank_x:nT { \xeCJK_get_inter_class_toks:nn { Boundary } { Others } } { \xeCJK_copy_inter_class_toks:nnnn { Boundary } { Others } { Boundary } { Default } } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_group_begin:,\@@_group_end:} % 用于保护下面歧义宽度标点的分组。 % \begin{macrocode} \cs_new_eq:NN \@@_group_begin: \group_begin: \cs_new_eq:NN \@@_group_end: \group_end: % \end{macrocode} % \end{macro} % % 单独处理宽度有分歧的几个标点:包括省略号、破折号、间隔号、引号等中西文混用的 % 符号, 保证其命令形式输出的是西文字体。并对一些编码的符号宏包做特殊处理。在 % 使用 \texttt{T1} 编码的时候,|\r{u}| 的实际定义是 |\char183| 与常被用作中文 % 间隔号的 \texttt{U+00B7} 冲突。 % \begin{macrocode} \@@_after_preamble:n { \tl_map_inline:nn { \textellipsis \textemdash \textperiodcentered \textcentereddot \textquoteleft \textquoteright \textquotedblleft \textquotedblright } { \cs_gset_protected_nopar:Npx #1 { \@@_group_begin: \makexeCJKinactive \exp_not:o {#1} \@@_group_end: } } \tl_put_left:Nn \tipaencoding { \makexeCJKinactive } \cs_new_eq:NN \@@_aux_r:n \r \cs_set_nopar:Npn \r #1 { \bool_if:nTF { \str_if_eq_x_p:nn { \f@encoding } { T1 } && \str_if_eq_x_p:nn {#1} { u } } { { \makexeCJKinactive \@@_aux_r:n {#1} } } { \@@_aux_r:n {#1} } } \xeCJK_if_package_loaded:nT { pifont } { \RenewDocumentCommand \Pifont { m } { \makexeCJKinactive \usefont { U } {#1} { m } { n } } } } % \end{macrocode} % % 简单处理与 \pkg{hyperref} 宏包的兼容问题。 % \begin{macrocode} \@@_after_end_preamble:n { \xeCJK_if_package_loaded:nT { hyperref } { \pdfstringdefDisableCommands { \@@_gobble_CJKfamily: \xeCJK_cs_clear:N \makexeCJKinactive \xeCJK_cs_clear:N \@@_group_begin: \xeCJK_cs_clear:N \@@_group_end: } } } % \end{macrocode} % % \changes{v3.1.0}{2012/11/13}{取消 \cs{cprotect} 的外部宏限制。} % 当探测到 \pkg{cprotect} 宏包被引入时,则取消 \cs{cprotect} 宏的 \cs{outer} 定义。 % \begin{macrocode} \@@_after_end_preamble:n { \bool_if:nT { \xeCJK_if_package_loaded_p:n { cprotect } && \cs_if_exist_p:N \icprotect } { \exp_after:wN \tex_let:D \cs:w cprotect \cs_end: \icprotect } } % \end{macrocode} % % \begin{macro}[internal]{\xeCJKcaption} % 可以使用 \pkg{CJK} 宏包中的 |.cpx| 文件。 % \begin{macrocode} \cs_if_exist:NF \CJK@ifundefined { \cs_set_eq:NN \CJK@ifundefined \cs_if_free:NTF } \NewDocumentCommand \xeCJKcaption { o m } { \IfNoValueF {#1} { \XeTeXdefaultencoding "#1" } \use:x { \char_set_catcode_letter:n { 64 } \file_input:n { #2.cpx } \char_set_catcode:nn { 64 } { \char_value_catcode:n { 64 } } } \XeTeXdefaultencoding "UTF-8" } % \end{macrocode} % \end{macro} % % 由于 \pkg{xeCJK} 禁止 \pkg{CJKulem} 的载入,因此当使用 \pkg{ctex} 宏包的 |fntef| % 选项时,就会出现 \cs{normalem} 没有定义的问题。此时改用 \pkg{xeCJKfntef} 以便 % 载入 \pkg{ulem}。 % % 判断过于繁琐,应该在 \pkg{ctex} 包中妥善处理。这段代码应在 \pkg{ctex} 包发布 % 新版本后删去。 % \begin{macrocode} \cs_if_eq:NNTF \ifCTEX@fntef \tex_iftrue:D { \AtEndOfPackage { \RequirePackage { xeCJKfntef } } } { \@@_at_end_preamble:n { \xeCJK_if_package_loaded:nF { xeCJKfntef } { \xeCJK_if_package_loaded:nTF { CJKfntef } { \RequirePackage { xeCJKfntef } } { \xeCJK_if_package_loaded:nT { ulem } { \RequirePackage { xeCJKfntef } } } } } } % \end{macrocode} % % 导言区末尾检测到 \pkg{listings} 时,自动载入 \pkg{xeCJK-listings}。 % \begin{macrocode} \@@_at_end_preamble:n { \xeCJK_if_package_loaded:nT { listings } { \RequirePackage { xeCJK-listings } } } % \end{macrocode} % % \changes{v3.2.4}{2013/06/25}{不再使用 \texttt{CJKnumber} 选项,可以在 % \pkg{xeCJK} 之后直接使用 \pkg{CJKnumb} 宏包得到中文数字。} % % \begin{macro}[internal]{\CJKaddEncHook} % 为使用 \pkg{CJKnumb} 宏包而作一些处理。另外 \pkg{CJKnumb} 使用的是传统汉字“萬” % 和“億”,我们在这里把它们修正为简体字。 % \begin{macrocode} \cs_new_protected:Npn \CJKaddEncHook #1#2 { \str_if_eq:nnT {#1} { \CJK@UnicodeEnc } { \group_begin: \cs_set_nopar:Npn \Unicode ##1##2 { (##1) * \c_two_hundred_fifty_six + (##2) } \cs_set_eq:NN \def \xeCJK_char_from_charcode:Nn #2 \group_end: \tl_gset:Nn \CJK@tenthousand { ^^^^4e07 } \tl_gset:Nn \CJK@hundredmillion { ^^^^4ebf } } } \cs_new_protected_nopar:Npn \xeCJK_char_from_charcode:Nn #1#2 { \group_begin: \char_set_lccode:nn { "4E00 } {#2} \tl_to_lowercase:n { \group_end: \tl_const:Nn #1 { ^^^^4e00 } } } \bool_if:NT \g_@@_number_bool { \RequirePackage { CJKnumb } } % \end{macrocode} % \end{macro} % % 最后引入本地配置文件。 % \begin{macrocode} \bool_if:NT \g_@@_config_bool { \tl_const:Nn \c_@@_config_ext_tl { cfg } \@onefilewithoptions { \g_@@_config_name_tl } [ ] [ ] { \c_@@_config_ext_tl } } % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % \subsection{\pkg{xeCJKfntef}} % % \changes{v3.1.1}{2012/12/08}{增加小宏包 \pkg{xeCJKfntef},用于处理下划线的问题。} % \changes{v3.2.4}{2013/06/23}{修正 \pkg{xeCJKfntef} 与 \pkg{natbib} 等的冲突。} % % \begin{macrocode} %<*fntef> % \end{macrocode} % % \pkg{xeCJKfntef} 不需要 \pkg{CJKulem} 宏包的支持,因此当使用 \pkg{CJKfntef} 时,% % 需要另行载入 \pkg{ulem}。 % \begin{macrocode} \PassOptionsToPackage { normalem } { ulem } \DeclareOption* { \PassOptionsToPackage { \CurrentOption } { ulem } } \ProcessOptions \scan_stop: % \end{macrocode} % % \begin{macrocode} \RequirePackage { xeCJK } \RequirePackage { ulem } \RequirePackage { CJKfntef } \RequirePackage { environ } % \end{macrocode} % % \begin{macrocode} \addto@hook \UL@hook { \xeCJK_hook_for_ulem: } % \end{macrocode} % % \begin{macro}[internal]{\xeCJK_hook_for_ulem:} % \changes{v3.1.0}{2012/11/16}{简化对 \pkg{ulem} 宏包的兼容补丁。} % \changes{v3.1.1}{2012/12/08}{完全处理下划线里的标点符号的有关问题。} % \begin{macrocode} \cs_new_protected_nopar:Npn \xeCJK_hook_for_ulem: { \bool_if:NF \l_@@_ulem_hook_used_bool { \bool_set_true:N \l_@@_ulem_hook_used_bool \xeCJKsetup { CheckFullRight = false , xCJKecglue = false } \bool_if:NTF \l_@@_ulem_skip_punct_bool { \cs_set_eq:NN \@@_ulem_leader_type: \UL@leadtype } { \xeCJK_cs_clear:N \@@_ulem_skip_punct_begin: \xeCJK_cs_clear:N \@@_ulem_skip_punct_end: } \@@_ulem_initial: \xeCJK_glue_to_skip:nN { \cs_set_eq:NN \ \tex_space:D \cs_set_eq:NN \penalty \tex_penalty:D \cs_set_eq:NN \hskip \skip_horizontal:N \CJKglue } \l_@@_ccglue_skip \xeCJK_glue_to_skip:nN { \cs_set_eq:NN \ \tex_space:D \cs_set_eq:NN \penalty \tex_penalty:D \cs_set_eq:NN \hskip \skip_horizontal:N \CJKecglue } \l_@@_ecglue_skip \cs_set_protected_nopar:Npn \CJKglue { \@@_ulem_glue:n \l_@@_ccglue_skip } \cs_set_protected_nopar:Npn \CJKecglue { \@@_ulem_glue:n \l_@@_ecglue_skip } } } \bool_new:N \l_@@_ulem_hook_used_bool % \end{macrocode} % \end{macro} % % \setbox\xeCJKtmpbox\vbox\bgroup\gobblelineno % \begin{macrocode} %<@@=> % \end{macrocode}\egroup % % \begin{macro}[internal]{\CJK@UL,\CJK@@UL} % 修改 \pkg{CJKfntef} 中的 \cs{CJK@UL} 和 \cs{CJK@@UL} 以适应下面的修改。 % \begin{macrocode} \cs_set_eq:NN \CJK@UL \CJK@@UL \tl_replace_once:Nnn \CJK@UL { \ULon } { \bool_set_true:N \l__xeCJK_ulem_skip_punct_bool \ULon } \tl_replace_once:Nnn \CJK@@UL { \ULon } { \bool_set_false:N \l__xeCJK_ulem_skip_punct_bool \ULon } \bool_new:N \l__xeCJK_ulem_skip_punct_bool % \end{macrocode} % \end{macro} % % \setbox\xeCJKtmpbox\vbox\bgroup\gobblelineno % \begin{macrocode} %<@@=xeCJK> % \end{macrocode}\egroup % % \begin{macro}[internal]{\@@_ulem_skip_punct_begin:,\@@_ulem_skip_punct_end:} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_ulem_skip_punct_begin: { \xeCJK_cs_clear:N \UL@leadtype } \cs_new_protected_nopar:Npn \@@_ulem_skip_punct_end: { \cs_set_eq:NN \UL@leadtype \@@_ulem_leader_type: } \xeCJK_cs_clear:N \@@_ulem_leader_type: % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_ulem_initial:} % 这里的设置是为了在下划线状态下,下划线可以自动跳过全角标点符号和正确的在它们 % 前/后断行,并且与行首行末对齐。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_ulem_initial: { \@@_ulem_swap_cs:NN \xeCJK_FullLeft_and_Default: \@@_ulem_FullLeft_and_Default: \xeCJK_FullLeft_and_CJK: \@@_ulem_FullLeft_and_CJK: \xeCJK_FullRight_and_Default: \@@_ulem_FullRight_and_Default: \xeCJK_FullRight_and_CJK: \@@_ulem_FullRight_and_CJK: \xeCJK_CJK_and_CJK:N \@@_ulem_CJK_and_CJK:N \xeCJK_Boundary_and_Default: \@@_ulem_Boundary_and_Default: \xeCJK_Boundary_and_NormalSp: \@@_ulem_Boundary_and_NormalSp: \xeCJK@fix@penalty \@@_ulem_fix_penalty: \@@_punct_hskip:n \@@_ulem_punct_hskip:n \@@_CJK_and_Boundary_aux: \@@_ulem_CJK_and_Boundary_aux: \@@_Default_and_FullLeft_glue:N \@@_ulem_Default_and_FullLeft_glue:N \@@_Default_and_FullRight_glue:N \@@_ulem_Default_and_FullRight_glue:N \@@_CJK_and_FullLeft_glue:N \@@_ulem_CJK_and_FullLeft_glue:N \@@_CJK_and_FullRight_glue:N \@@_ulem_CJK_and_FullRight_glue:N \@@_Boundary_and_FullLeft_glue:N \@@_ulem_Boundary_and_FullLeft_glue:N \q_recursion_tail \q_nil \q_recursion_stop \seq_map_inline:Nn \g_@@_CJK_sub_class_seq { \seq_map_inline:Nn \g_@@_CJK_sub_class_seq { \str_if_eq:nnTF {##1} {####1} { \xeCJK_inter_class_toks:nnn { CJK } { CJK/##1 } { \@@_ulem_between_CJK_blocks:nnN { CJK } {##1} } \xeCJK_inter_class_toks:nnn { CJK/##1 } { CJK/##1 } { \@@_ulem_between_CJK_blocks:nnN { CJK } {##1} } } { \xeCJK_inter_class_toks:nnn { CJK/##1 } { CJK/####1 } { \@@_ulem_between_CJK_blocks:nnN {##1} {####1} } } } } } \cs_new_protected_nopar:Npn \@@_ulem_swap_cs:NN #1#2 { \quark_if_recursion_tail_stop:N #1 \xeCJK_swap_cs:NN #1#2 \@@_ulem_swap_cs:NN } % \end{macrocode} % \end{macro} % % \changes{v3.1.2}{2012/12/27}{解决在下划线状态下使用 \cs{makebox} 时的错误。} % % \begin{macro}[internal]{\xeCJK_if_ulem_patch:TF} % 在下划线状态下,\pkg{ulem} 宏包在数学模式或者盒子中使用 \cs{UL@hrest} 恢复 % \verb*|\ | 等的定义,此时不需要使用 \cs{UL@stop} 和 \cs{UL@start} 来断开下划线而 % 产生断点。 % \begin{macrocode} \cs_new_nopar:Npn \xeCJK_if_ulem_patch:TF { \if_meaning:w \ \LA@space \exp_after:wN \use_ii:nn \else: \exp_after:wN \use_i:nn \fi: } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_ulem_Boundary_and_Default:} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_ulem_Boundary_and_Default: { \xeCJK_if_ulem_patch:TF { \xeCJK_if_last_node:nTF { CJK } { \xeCJK_remove_node: \skip_horizontal:N \l_@@_ecglue_skip } { \xeCJK_if_last_node:nT { CJK-space } { \xeCJK_remove_node: \c_space_tl } } } { \@@_ulem_Boundary_and_Default: } } % \end{macrocode} % \end{macro} % % % \begin{macro}[internal]{\@@_ulem_Boundary_and_NormalSp:} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_ulem_Boundary_and_NormalSp: { \xeCJK_if_ulem_patch:TF { \xeCJK_if_last_node:nT { CJK-space } { \xeCJK_remove_node: \c_space_tl } } { \@@_ulem_Boundary_and_NormalSp: } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_ulem_CJK_and_Boundary_aux:} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_ulem_CJK_and_Boundary_aux: { \xeCJK_if_ulem_patch:TF { \UL@stop \@@_ulem_hskip:n { \c_zero_skip } \UL@start { \xeCJK_make_node:n { CJK } } } { \@@_ulem_CJK_and_Boundary_aux: } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_ulem_fix_penalty:} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_ulem_fix_penalty: { \xeCJK_if_ulem_patch:TF { \fix@penalty } { \@@_ulem_fix_penalty: } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_ulem_CJK_and_CJK:N} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_ulem_CJK_and_CJK:N { \xeCJK_if_ulem_patch:TF { \xeCJK_class_group_end: \UL@stop \@@_ulem_ccglue: \UL@start \@@_ulem_class_group_begin: \CJKsymbol } { \@@_ulem_CJK_and_CJK:N } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_ulem_class_group_begin:} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_ulem_class_group_begin: { \xeCJK_class_group_begin: \xeCJK_clear_Boundary_and_CJK_toks: \xeCJK_select_font: } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_ulem_between_CJK_blocks:nnN} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_ulem_between_CJK_blocks:nnN #1#2 { \xeCJK_if_ulem_patch:TF { \xeCJK_class_group_end: \UL@stop \@@_ulem_ccglue: \UL@start \xeCJK_class_group_begin: \xeCJK_clear_Boundary_and_CJK_toks: \@@_switch_font:nn {#1} {#2} \CJKsymbol } { \skip_horizontal:N \l_@@_ccglue_skip \@@_switch_font:nn {#1} {#2} \CJKsymbol } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_ulem_Default_and_FullLeft_glue:N} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_ulem_Default_and_FullLeft_glue:N #1 { \xeCJK_if_ulem_patch:TF { \UL@stop \@@_ulem_skip_punct_begin: \@@_punct_glue:NN \c_@@_left_tl {#1} \UL@start } { \@@_ulem_Default_and_FullLeft_glue:N #1 } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_ulem_Boundary_and_FullLeft_glue:N} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_ulem_Boundary_and_FullLeft_glue:N #1 { \xeCJK_if_ulem_patch:TF { \UL@stop \@@_ulem_skip_punct_begin: \int_compare:nNnF \etex_lastnodetype:D = \c_one { \@@_punct_glue:NN \c_@@_left_tl {#1} } \UL@start } { \@@_ulem_Boundary_and_FullLeft_glue:N #1 } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_ulem_CJK_and_FullLeft_glue:N} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_ulem_CJK_and_FullLeft_glue:N #1 { \xeCJK_if_ulem_patch:TF { \xeCJK_class_group_end: \UL@stop \@@_ulem_skip_punct_begin: \@@_ulem_ccglue: \@@_punct_glue:NN \c_@@_left_tl {#1} \UL@start \@@_ulem_class_group_begin: } { \@@_ulem_CJK_and_FullLeft_glue:N #1 } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_ulem_Default_and_FullRight_glue:N} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_ulem_Default_and_FullRight_glue:N #1 { \xeCJK_if_ulem_patch:TF { \UL@stop \@@_ulem_skip_punct_begin: \@@_punct_if_long:NTF {#1} { \@@_ulem_ccglue: } { \xeCJK_no_break: \@@_punct_if_middle:NT {#1} { \@@_punct_glue:NN \c_@@_right_tl {#1} } } \UL@start } { \@@_ulem_Default_and_FullRight_glue:N #1 } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_ulem_CJK_and_FullRight_glue:N} % \changes{v3.2.2}{2013/05/30}{修正下划线不能跳过全角右标点的问题。} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_ulem_CJK_and_FullRight_glue:N #1 { \xeCJK_if_ulem_patch:TF { \xeCJK_class_group_end: \@@_Default_and_FullRight_glue:N {#1} \@@_ulem_class_group_begin: } { \@@_ulem_CJK_and_FullRight_glue:N #1 } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_ulem_FullLeft_and_Default:} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_ulem_FullLeft_and_Default: { \xeCJK_if_ulem_patch:TF { \@@_punct_if_middle:NTF \g_@@_last_punct_tl { \xeCJK_get_punct_bounds:NN \c_@@_left_tl \g_@@_last_punct_tl \@@_punct_rule:NN \c_@@_right_tl \g_@@_last_punct_tl \xeCJK_class_group_end: \UL@stop \xeCJK_no_break: \@@_punct_glue:NN \c_@@_left_tl \g_@@_last_punct_tl } { \xeCJK_class_group_end: \UL@stop } \@@_ulem_skip_punct_end: \xeCJK_no_break: \UL@start } { \@@_ulem_FullLeft_and_Default: } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_ulem_FullLeft_and_CJK:} % \changes{v3.2.3}{2013/06/04} % {修正全角左标点后下划线与 \cs{CJKunderdot} 连用时结果不正常的问题。} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_ulem_FullLeft_and_CJK: { \xeCJK_if_ulem_patch:TF { \xeCJK_FullLeft_and_Default: \@@_ulem_class_group_begin: } { \@@_ulem_FullLeft_and_CJK: } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_ulem_FullRight_and_Default:} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_ulem_FullRight_and_Default: { \xeCJK_if_ulem_patch:TF { \@@_punct_rule:NN \c_@@_right_tl \g_@@_last_punct_tl \xeCJK_class_group_end: \UL@stop \@@_punct_glue:NN \c_@@_right_tl \g_@@_last_punct_tl \@@_ulem_skip_punct_end: \UL@start } { \@@_ulem_FullRight_and_Default: } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_ulem_FullRight_and_CJK:} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_ulem_FullRight_and_CJK: { \xeCJK_if_ulem_patch:TF { \@@_punct_rule:NN \c_@@_right_tl \g_@@_last_punct_tl \xeCJK_class_group_end: \UL@stop \@@_punct_glue:NN \c_@@_right_tl \g_@@_last_punct_tl \@@_ulem_ccglue: \@@_ulem_skip_punct_end: \UL@start \@@_ulem_class_group_begin: } { \@@_ulem_FullRight_and_CJK: } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_ulem_punct_hskip:n} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_ulem_punct_hskip:n { \xeCJK_if_ulem_patch:TF { \@@_ulem_hskip:n } { \@@_ulem_punct_hskip:n } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_ulem_glue:n,\@@_ulem_ccglue:,\@@_ulem_hskip:n} % 在下划线状态下的分别代替 \cs{CJKglue} 等。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_ulem_glue:n #1 { \xeCJK_if_ulem_patch:TF { \UL@stop \@@_ulem_hskip:n {#1} \UL@start } { \skip_horizontal:n {#1} } } \cs_new_protected_nopar:Npn \@@_ulem_ccglue: { \skip_set_eq:NN \UL@skip \l_@@_ccglue_skip \UL@leaders } \cs_new_protected_nopar:Npn \@@_ulem_hskip:n #1 { \int_compare:nNnTF \tex_lastkern:D = \c_three { \skip_horizontal:n {#1} } { \skip_set:Nn \UL@skip {#1} \UL@leaders } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\CJKunderdot} % 使用 \pkg{xeCJK} 时,\pkg{CJKfntef} 中的 \cs{CJKunderdot} 和 \cs{CJKunderanysymbol} % 在汉字之间不能断行。因此需要我们在这里修改它们。 % \begin{macrocode} \RenewDocumentCommand \CJKunderdot { m } { \bool_if:NT \l_@@_ulem_hook_used_bool { \UL@stop \@@_ulem_restore_CJK_and_Boundary: } \CJK@preUnderdot \@@_make_under_symbol:n { \CJK@underdotSkip } \cs_gset_eq:NN \@@_save_under_dot_CJKsymbol:N \CJKsymbol \cs_set_eq:NN \CJKsymbol \@@_under_CJKsymbol:N \@@_restore_output_CJKsymbol: \bool_if:NT \l_@@_ulem_hook_used_bool { \UL@start } #1 \bool_if:NT \l_@@_ulem_hook_used_bool { \UL@stop } \cs_set_eq:NN \CJKsymbol \@@_save_under_dot_CJKsymbol:N \tex_output:D \exp_after:wN { \l_@@_underdot_output_tl } \CJK@postUnderdot \bool_if:NT \l_@@_ulem_hook_used_bool { \@@_ulem_restore_CJK_and_Boundary: \UL@start } \tex_ignorespaces:D } \box_new:N \g_@@_under_symbol_box \cs_new_protected_nopar:Npn \@@_ulem_restore_CJK_and_Boundary: { \xeCJK_if_ulem_patch:TF { \xeCJK_swap_cs:NN \@@_CJK_and_Boundary_aux: \@@_ulem_CJK_and_Boundary_aux: } { } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\CJKunderanysymbol} % \begin{macrocode} \RenewDocumentCommand \CJKunderanysymbol { m m m } { \group_begin: \hbox_set:Nn \CJK@underdotBox {#2} \@@_make_under_symbol:n {#1} \cs_gset_eq:NN \@@_save_under_dot_CJKsymbol:N \CJKsymbol \cs_set_eq:NN \CJKsymbol \@@_under_CJKsymbol:N \@@_restore_output_CJKsymbol: #3 \group_end: \tex_ignorespaces:D } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_restore_output_CJKsymbol:} % \changes{v3.2.3}{2013/06/04}{解决 \cs{CJKunderdot} 跨页使用时影响到页眉页脚的问题。} % \cs{CJKunderdot} 中对 \cs{CJKsymbol} 的修改会影响到页眉和页脚,需要小心处理。 % \begin{macrocode} \cs_new_protected:Npn \@@_restore_output_CJKsymbol: { \tl_set:Nx \l_@@_underdot_output_tl { \exp_after:wN \exp_not:n \tex_the:D \tex_output:D } \tex_output:D \exp_after:wN { \exp_after:wN \cs_set_eq:NN \exp_after:wN \CJKsymbol \exp_after:wN \@@_save_under_dot_CJKsymbol:N \l_@@_underdot_output_tl } } \tl_new:N \l_@@_underdot_output_tl % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_make_under_symbol:n} % \begin{macrocode} \cs_new_protected:Npn \@@_make_under_symbol:n #1 { \hbox_set:Nn \l_@@_tmp_box { ^^^^4e00 } \vbox_gset_to_ht:Nnn \g_@@_under_symbol_box \c_zero_dim { \skip_vertical:n {#1} \hbox_to_zero:n { \tex_kern:D - \box_wd:N \l_@@_tmp_box \tex_hss:D \box_use:N \CJK@underdotBox \tex_hss:D } \tex_vss:D } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_under_CJKsymbol:N} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_under_CJKsymbol:N #1 { \@@_save_under_dot_CJKsymbol:N {#1} \hbox_overlap_left:n { \box_use:N \g_@@_under_symbol_box } { \xeCJK_make_node:n { CJK } } \xeCJK_ignore_spaces:w } % \end{macrocode} % \end{macro} % % % \begin{macro}[internal]{CJKfilltwosides} % \changes{v3.2.4}{2012/06/26}{改用 \texttt{minipage} 和 \LaTeX 表格(\texttt{tabular})来实现。} % 使用 \texttt{minipage} 和 \LaTeX 表格(\texttt{tabular})来定义 |CJKfilltwosides| 环境。 % 可选参数 |#1| 表示环境的垂直对齐位置,默认居中;参数 |#2| 表示环境的宽度。 % 带星号的环境,如果 |#2| 不大于零或者不大于环境最长文本行的宽度,则取环境的自然宽度。 % \begin{macrocode} \RenewDocumentEnvironment { CJKfilltwosides } { O { c } m } { \use:x { \exp_not:N \minipage [#1] { \dim_eval:n {#2} } } \cs_set_eq:NN \CJKglue \tex_hfill:D } { \endminipage \ignorespacesafterend } \NewEnviron { CJKfilltwosides* } [ 2 ] [ c ] { \cs_set_eq:NN \CJKglue \tex_hfill:D \tl_set:Nn \arraystretch { 1 } \token_if_dim_register:NT \extrarowheight { \dim_set_eq:NN \extrarowheight \c_zero_dim } \dim_compare:nNnTF {#2} > \c_zero_dim { \hbox_set:Nn \l_@@_tmp_box { \tabular [#1] { @ { } c @ { } } \BODY \endtabular } \dim_compare:nNnTF {#2} > { \box_wd:N \l_@@_tmp_box } { \tabular [#1] { @ { } p { \dim_eval:n {#2} } @ { } } \BODY \endtabular } { \hbox_unpack:N \l_@@_tmp_box } } { \tabular [#1] { @ { } c @ { } } \BODY \endtabular } } [ \ignorespacesafterend ] % \end{macrocode} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % % \subsection{\pkg{xeCJK-listings}} % % \changes{v3.2.2}{2012/06/04}{增加小宏包 \pkg{xeCJK-listings},用于支持 \pkg{listings} 宏包。} % \changes{v3.2.3}{2012/06/06}{完善对 \pkg{listings} 宏包的支持。} % % 仿照 \package{luatexja} 宏包中 \pkg{lltjp-listings} 的处理,支持 \package{listings} 宏包。 % % \begin{macrocode} %<*listings> % \end{macrocode} % % \begin{macrocode} \DeclareOption* { \PassOptionsToPackage { \CurrentOption } { xeCJK } } \ProcessOptions \scan_stop: % \end{macrocode} % % \begin{macrocode} \RequirePackage { xeCJK } \RequirePackage { listings } % \end{macrocode} % % \begin{macrocode} \lst@AddToHook { Init } { \@@_listings_initial_hook: } \lst@AddToHook { SelectCharTable } { \@@_listings_toks_hook: } \lst@AddToHook { OutputBox } { \tl_set_eq:NN \l_xeCJK_punct_style_tl \c_@@_punct_style_plain_tl \l_@@_restore_listings_toks_tl \@@_listings_output_IVS: } \lst@AddToHook { PreSet } { \bool_set_true:N \l_@@_listings_env_bool } % \end{macrocode} % % \begin{macro}[internal]{\@@_listings_initial_hook:} % \changes{v3.2.3}{2013/06/04} % {解决 \texttt{listings} 坏境中代码行号输出不正确的问题,并解决在其中跨页时对页眉 % 和页脚的影响。} % 为使代码行号结果正确,需要在 \cs{lst@numberstyle} 中恢复 \cs{XeTeXinterchartoks}。 % 在 \texttt{listings} 环境中换页时,对 \cs{XeTeXinterchartoks} 的修改会影响到 % 页眉和页脚,需要在 \cs{output} 中恢复成正常定义。这里使用 \cs{use:n} 是为了在 % \cs{tex_output:D} 中不增加额外的分组。加入 \cs{tex_noindent:D} 是为了防止汉字 % 出现在首行的时候可能会产生额外空行。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_listings_initial_hook: { \tex_noindent:D \bool_gset_false:N \g_@@_listings_IVS_bool \tl_put_left:Nn \lst@numberstyle { \l_@@_restore_listings_toks_tl } \tex_output:D \exp_after:wN \exp_after:wN \exp_after:wN { \exp_after:wN \exp_after:wN \exp_after:wN \l_@@_restore_listings_toks_tl \exp_after:wN \use:n \tex_the:D \tex_output:D } \lst@ifbreaklines \cs_set_eq:NN \@@_listings_CJK_toks: \@@_listings_breaklines_toks: \fi: } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_listings_toks_hook:} % 采用不同的 \cs{XeTeXinterchartoks} 处理方式,输入的时候是将汉字加入到 \pkg{listings} % 的输出队列,实际输出的时候是普通文字。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_listings_toks_hook: { \tl_set:Nx \l_@@_restore_listings_toks_tl { \@@_backup_inter_class_toks:nn { Boundary } { Default } \@@_backup_inter_class_toks:nn { Boundary } { CJK } \@@_backup_inter_class_toks:nn { Boundary } { IVS } \@@_backup_inter_class_toks:nn { Boundary } { FullLeft } \@@_backup_inter_class_toks:nn { Boundary } { FullRight } } \seq_map_inline:Nn \g_@@_CJK_sub_class_seq { \tl_put_right:Nx \l_@@_restore_listings_toks_tl { \@@_backup_inter_class_toks:nn { Boundary } { CJK/##1 } } } \xeCJK_inter_class_toks:nnn { Boundary } { Default } { \@@_listings_process_Default:N } \xeCJK_inter_class_toks:nnn { Boundary } { IVS } { \@@_listings_process_IVS:nN { \c_zero } } \@@_listings_CJK_toks_hook: } \tl_new:N \l_@@_restore_listings_toks_tl \cs_new_nopar:Npn \@@_backup_inter_class_toks:nn #1#2 { \xeCJK_inter_class_toks:nnn {#1} {#2} { \xeCJK_get_inter_class_toks:nn {#1} {#2} } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_listings_CJK_toks_hook:,\@@_listings_breaklines_toks:} % 根据 \texttt{breaklines} 选项的使用与否,选择不同的处理方式。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_listings_CJK_toks_hook: { \xeCJK_inter_class_toks:nnn { Boundary } { CJK } { \@@_listings_process_CJK:nN { \c_two } } \xeCJK_inter_class_toks:nnn { Boundary } { FullLeft } { \@@_listings_process_CJK:nN { \c_two } } \xeCJK_inter_class_toks:nnn { Boundary } { FullRight } { \@@_listings_process_CJK:nN { \c_two } } \seq_map_inline:Nn \g_@@_CJK_sub_class_seq { \xeCJK_inter_class_toks:nnn { Boundary } { CJK/##1 } { \@@_listings_process_CJK:nN { \c_two } } } } \cs_new_protected_nopar:Npn \@@_listings_breaklines_toks: { \xeCJK_inter_class_toks:nnn { Boundary } { CJK } { \@@_listings_process_breaklines_CJK:nN { \c_two } } \xeCJK_inter_class_toks:nnn { Boundary } { FullLeft } { \@@_listings_process_FullLeft:nN { \c_two } } \xeCJK_inter_class_toks:nnn { Boundary } { FullRight } { \@@_listings_process_FullRight:nN { \c_two } } \seq_map_inline:Nn \g_@@_CJK_sub_class_seq { \xeCJK_inter_class_toks:nnn { Boundary } { CJK/##1 } { \@@_listings_process_breaklines_CJK:nN { \c_two } } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_listings_process_Default:N,\@@_listings_process_CJK:nN} % \changes{v3.2.3}{2013/06/08}{在 \texttt{listings} 坏境中对 \cs{charcode} 大于 % $255$ 的字符根据其 \cs{catcode} 区分 \texttt{letter} 和 \texttt{other}。} % 对于 \cs{charcode} 大于 $255$ 的字符,根据 \cs{catcode} 进行处理。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_listings_process_Default:N #1 { \token_if_letter:NTF #1 { \lst@ProcessLetter #1 } { \lst@ProcessOther #1 } } \cs_new_protected_nopar:Npn \@@_listings_process_CJK:nN #1#2 { \token_if_letter:NTF #2 { \@@_listings_process_letter:nN {#1} #2 } { \@@_listings_process_other:nN {#1} #2 } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_listings_append:nN} % 普通 CJK 字符的宽度为一般基本宽度的两倍,IVS 类不增加宽度。这里有一个问题, % 对 CJK 字符类中的一些半角字符(例如半角日文假名)没有区分开。\pkg{listings} 通过 % 重定义 \cs{lst@Append} 将代码写入外部文件,因此需要保留。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_listings_append:nN #1#2 { \int_add:Nn \lst@length { #1 - \c_one } \lst@Append #2 } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_listings_process_letter:nN,\@@_listings_process_other:nN} % 在 \texttt{letter} 类中区分汉字和西文字母。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_listings_process_letter:nN { \lst@whitespacefalse \bool_if:NTF \l_@@_listings_letter_bool { \lst@lettertrue } { \lst@ifletter \lst@Output \else: \lst@OutputOther \lst@lettertrue \fi: \bool_set_true:N \l_@@_listings_letter_bool } \@@_listings_append:nN } \cs_new_protected_nopar:Npn \@@_listings_process_other:nN #1#2 { \lst@whitespacefalse \bool_if:NTF \l_@@_listings_letter_bool { \lst@Output \lst@letterfalse \bool_set_false:N \l_@@_listings_letter_bool } { \lst@ifletter \lst@Output \lst@letterfalse \fi: } \cs_set_eq:NN \lst@lastother #2 \@@_listings_append:nN {#1} #2 } % \end{macrocode} % \end{macro} % % \changes{v3.2.4}{2012/07/05} % {使 \pkg{listings} 的 \texttt{breaklines} 选项对 CJK 字符类可用,并保持标点符号的禁则。} % % \begin{macro}[internal] % {\@@_listings_process_breaklines_CJK:nN, % \@@_listings_process_FullLeft:nN, % \@@_listings_process_FullRight:nN} % 当使用 \texttt{breaklines} 选项时,立即输出之前的单个文字,以便于断行。并将标点 % 与它前/后的 CJK 文字放在同一个盒子中,以保持禁则。但是不能区分 letter 和 other。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_listings_process_breaklines_CJK:nN { \lst@whitespacefalse \bool_if:NTF \l_@@_listings_letter_bool { \int_compare:nNnF \l_@@_listings_flag_int = \c_two { \lst@Output } \lst@lettertrue } { \lst@ifletter \lst@Output \else: \lst@OutputOther \lst@lettertrue \fi: \bool_set_true:N \l_@@_listings_letter_bool } \int_set_eq:NN \l_@@_listings_flag_int \c_one \@@_listings_append:nN } \cs_new_protected_nopar:Npn \@@_listings_process_FullLeft:nN #1#2 { \lst@whitespacefalse \bool_if:NTF \l_@@_listings_letter_bool { \bool_if:nF { \int_compare_p:nNn \l_@@_listings_flag_int = \c_two || ( \int_compare_p:nNn \l_@@_listings_flag_int = \c_three && ! \l_@@_punct_breakable_bool ) } { \lst@Output } \lst@lettertrue } { \lst@ifletter \lst@Output \else: \lst@OutputOther \lst@lettertrue \fi: \bool_set_true:N \l_@@_listings_letter_bool } \int_set_eq:NN \l_@@_listings_flag_int \c_two \@@_listings_append:nN {#1} #2 } \cs_new_protected_nopar:Npn \@@_listings_process_FullRight:nN #1#2 { \lst@whitespacefalse \bool_if:NTF \l_@@_listings_letter_bool { \bool_if:nT { \int_compare_p:nNn \l_@@_listings_flag_int < \c_two && \@@_punct_if_long_p:N #2 } { \lst@Output } \lst@lettertrue } { \lst@ifletter \lst@Output \else: \lst@OutputOther \lst@lettertrue \fi: \bool_set_true:N \l_@@_listings_letter_bool } \int_set_eq:NN \l_@@_listings_flag_int \c_three \@@_listings_append:nN {#1} #2 } \int_new:N \l_@@_listings_flag_int % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\lst@AppendLetter,\lst@AppendOther} % \begin{macrocode} \cs_set_protected_nopar:Npn \lst@AppendLetter { \bool_if:NTF \l_@@_listings_letter_bool { \lst@Output \lst@lettertrue \bool_set_false:N \l_@@_listings_letter_bool } { \reverse_if:N \lst@ifletter \lst@OutputOther \lst@lettertrue \fi: } \lst@ifbreaklines \int_zero:N \l_@@_listings_flag_int \fi: \lst@Append } \cs_set_protected_nopar:Npn \lst@AppendOther { \bool_if:NTF \l_@@_listings_letter_bool { \lst@Output \lst@letterfalse \bool_set_false:N \l_@@_listings_letter_bool } { \lst@ifletter \lst@Output \lst@letterfalse \fi: } \lst@ifbreaklines \int_zero:N \l_@@_listings_flag_int \fi: \tex_futurelet:D \lst@lastother \lst@Append } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_listings_process_IVS:nN} % \texttt{IVS} 类作为 \texttt{letter} 处理,不用增加 \cs{lst@length}。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_listings_process_IVS:nN { \reverse_if:N \lst@ifflexible \bool_gset_true:N \g_@@_listings_IVS_bool \fi: \@@_listings_process_letter:nN } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_listings_output_IVS:} % 在使用 \texttt{columns=fixed} 选项时,\pkg{listings} 会在输出盒子里的每个字符 % 之间加入 \cs{hss},这就破坏了 \XeTeX 将基本字和 IVS 正确的组合起来。 % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_listings_output_IVS: { \reverse_if:N \lst@ifflexible \bool_if:NT \g_@@_listings_IVS_bool { \bool_gset_false:N \g_@@_listings_IVS_bool \xeCJK_cs_clear:N \lst@FillOutputBox \cs_set_eq:NN \CJKglue \tex_hss:D } \fi: } \bool_new:N \g_@@_listings_IVS_bool % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_listings_peek_active_loop:TF} % \cs{lstinline} 通过判断参数中第一个字符是否是 \texttt{active} 类来区分 % 它是否被用在其它宏的参数之中。如果这第一个字符不在 \pkg{listings} 预定义的 % 符号表中,判断就会出问题。我们在这里通过一个循环跳过这些字符。 % \begin{macrocode} \cs_new_protected:Npn \@@_listings_peek_active_loop:TF #1#2#3 { \token_if_active:NTF #3 { #1#3 } { \token_if_cs:NTF #3 { #2#3 } { \int_compare:nNnTF { `#3 } > { \lst@ifec 255 \else: 127 \fi: } { \@@_listings_peek_active_loop:TF { #1#3 } { #2#3 } } { #2#3 } } } } \cs_set_eq:NN \lst@IfNextCharActive \@@_listings_peek_active_loop:TF % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_listings_inside_convert:nw,\@@_listings_inline_group:w} % 当 \cs{lstinline} 被使用在参数中时,\pkg{listings} 会使用一个循环逐个将 % \cs{lstinline} 参数中的字符设置为活动字符。我们可以通过 \cs{tl_set_rescan:Nnn} % 来完成这里的 \cs{catcode} 转换,避免将 \cs{charcode} 超过 $255$ 的字符都设置为 % 活动字符。 % \begin{macrocode} \cs_new_protected:Npn \@@_listings_inside_convert:nw #1 ~ \@empty { \tl_set_rescan:Nnn \l_@@_tmp_tl { } {#1} \@@_set_listings_escape: \tl_put_right:NV \lst@arg \l_@@_tmp_tl } \cs_set_eq:NN \lst@InsideConvert@ \@@_listings_inside_convert:nw \cs_new_protected_nopar:Npn \@@_listings_inline_group:w { \exp_after:wN \@@_listings_inline_group:n \exp_after:wN { \if_false: } \fi: } \cs_set_eq:NN \lst@InlineGJ \@@_listings_inline_group:w \cs_new_protected:Npn \@@_listings_inline_group:n #1 { \tl_set_rescan:Nnn \lst@arg { } {#1} \@@_set_listings_escape: \lst@InlineGJEnd } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_set_listings_escape:} % 由于我们在上面的修改,需要保留 |\| 用于转义 \cs{lstinline} 参数中的某些 \TeX % 特殊字符,与原来宏包一致。 % \begin{macrocode} \group_begin: \cs_set:Npn \@@_tmp:w #1 { \group_end: \cs_new_protected:Npn \@@_set_listings_escape: { \xeCJK_swap_cs:NN #1 \@@_listings_escape:N } \cs_new_protected:Npn \@@_listings_escape:N ##1 { \cs_if_eq:NNTF #1 ##1 { \@@_listings_escape:N } {##1} } } \use:n { \char_set_catcode_active:N \\ \@@_tmp:w } { \ } % \end{macrocode} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % % \setbox\xeCJKtmpbox\vbox\bgroup\gobblelineno % \begin{macrocode} %<@@=xunadd> % \end{macrocode}\egroup % % \subsection{\pkg{xunicode-addon}} % % \changes{v3.2.5}{2012/07/18} % {增加小宏包 \pkg{xunicode-addon},为 \pkg{xunicode} 提供判断字符是否存在的功能。} % % \begin{macrocode} %<*xunicode> % \end{macrocode} % % \pkg{xunicode} 对编码相关的符号命令的定义中用的是诸如 |\char"0022\relax| 的形式。 % 例如 \cs{textbar} 被展开为 |\char"007C\relax|。并且诸如下述的定义是无效的: % \begin{verbatim} % \DeclareUTFcomposite[\UTFencname]{x1EBF}{\'}{\^e} % \end{verbatim} % 我们在这里做的修改是把符号命令定义为实际的字符并且使上述定义生效。另外在使用 % 这些符号命令的时候,先判断当前字体中是否存在对应的字符,如果不存在,则使用这 % 些符号命令的默认设置。 % % \begin{macrocode} \pdftex_if_engine:T { \msg_new:nnnn { xunicode-addon } { cannot-use-pdftex } { This~package~requires~either~XeTeX~or~LuaTeX~to~function.} { You~must~change~your~typesetting~engine~to,~e.g.,\\ "xelatex"~or~"lualatex"~instead~of~plain~"latex"~or~"pdflatex". } \msg_critical:nn { xunicode-addon } { cannot-use-pdftex } } \RequirePackage { xparse } % \end{macrocode} % % 宏包选项是编码的名字。 % % \begin{macrocode} \clist_new:N \g_@@_encname_clist \DeclareOption* { \clist_gput_left:NV \g_@@_encname_clist \CurrentOption } \ProcessOptions \scan_stop: \tl_if_exist:NT \UTFencname { \clist_gput_left:Nx \g_@@_encname_clist { \UTFencname } } % \end{macrocode} % % 若 \pkg{xunicode} 已经被调用,则在宏包结束的时候,重新设置 \cs{UTFencname} % 对应的编码命令。否则设置 \cs{UTFencname},如果使用的是 \hologo{LuaLaTeX},则 % 需要作一些设置,使得 \pkg{xunicode} 可用。 % % \begin{macrocode} \@ifpackageloaded { xunicode } { } { \clist_get:NNF \g_@@_encname_clist \UTFencname { \xetex_if_engine:TF { \tl_set:Nn \UTFencname { EU1 } } { \tl_set:Nn \UTFencname { EU2 } } \clist_set_eq:NN \g_@@_encname_clist \UTFencname } \xetex_if_engine:TF { \RequirePackage { xunicode } } { \cs_set_eq:NN \@@_tmp:w \XeTeXpicfile \cs_set_eq:NN \XeTeXpicfile \prg_do_nothing: \RequirePackage { xunicode } \cs_set_eq:NN \XeTeXpicfile \@@_tmp:w } } \AtEndOfPackage { \ReloadXunicode { \g_@@_encname_clist } } % \end{macrocode} % % \begin{macro}[internal]{\ReloadXunicode} % 参数可以是多个编码,设置这些编码对应的命令。如果编码没有预先声明,则给出 % 一个错误警告。 % \begin{macrocode} \RenewDocumentCommand \ReloadXunicode { m } { \clist_set:Nx \l_@@_encname_clist {#1} \clist_remove_duplicates:N \l_@@_encname_clist \use:x { \bool_if:NT \l__kernel_expl_bool { \ExplSyntaxOff } \char_set_catcode_letter:n { 64 } \@@_reload:N \exp_not:N \l_@@_encname_clist \char_set_catcode:nn { 64 } { \char_value_catcode:n { 64 } } \bool_if:NT \l__kernel_expl_bool { \ExplSyntaxOn } } } \cs_new_protected:Npn \@@_reload:N #1 { \cs_set_eq:NN \@@_tmp:w \iftipaonetoken \cs_set_eq:NN \iftipaonetoken \scan_stop: \clist_map_inline:Nn #1 { \cs_if_exist:cTF { T@ ##1 } { \tl_set:Nx \UTFencname {##1} \clist_gput_right:Nx \g_@@_encname_clist {##1} \file_input:n { xunicode.sty } } { \msg_error:nnn { xunicode-addon } { encoding-unknown } {##1} } } \cs_set_eq:NN \iftipaonetoken \@@_tmp:w \clist_gremove_duplicates:N \g_@@_encname_clist } \clist_new:N \l_@@_encname_clist \msg_new:nnnn { xunicode-addon } { encoding-unknown } {Encoding~scheme~"#1"~unknown.} { You~may~use \\\\ \token_to_str:N \usepackage [ #1 , \encodingdefault ] {fontenc} \\\\ before~xunicode-addon~or~xunicode. } % \end{macrocode} % \end{macro} % % \begin{macro}[internal,pTF]{\@@_glyph_if_exist:n} % 判断字符在当前字体中是否存在。 % \begin{macrocode} \prg_new_conditional:Npnn \@@_glyph_if_exist:n #1 { p , T , F , TF } { \etex_iffontchar:D \tex_font:D \etex_numexpr:D #1 \scan_stop: \prg_return_true: \else: \prg_return_false: \fi: } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\UndeclareUTFcharacter} % 取消编码 |#1| 下的符号命令 |#3|。 % \begin{macrocode} \RenewDocumentCommand \UndeclareUTFcharacter { O { \UTFencname } m m } { \@@_if_csname:nTF {#3} { \UndeclareTextCommand {#3} } { \exp_args:Nc \UndeclareTextCommand { \tl_to_str:n {#3} } } {#1} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\UndeclareUTFcomposite} % 取消编码 |#1| 下的复合符号命令 |#3{#4}|。 % \begin{macrocode} \RenewDocumentCommand \UndeclareUTFcomposite { O { \UTFencname } m m m } { \@@_if_csname:nTF {#3} { \@@_undeclare_composite:Nnnn #3 } { \exp_args:Nc \@@_undeclare_composite:Nnnn { \tl_to_str:n {#3} } } {#1} {#4} {#2} } \cs_new_protected:Npn \@@_undeclare_composite:Nnnn #1#2#3#4 { \cs_undefine:c { \token_to_str:c {#2} \token_to_str:N #1 - \tl_to_str:n {#3} } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_if_csname:nTF} % 判断 |#1| 是否可以作为控制序列的名字。这是因为 \pkg{xunicide} 使用了下面的定义。 % \begin{verbatim} % \DeclareUTFcharacter[\UTFencname]{x0149}{'n} % \end{verbatim} % \begin{macrocode} \prg_new_conditional:Npnn \@@_if_csname:n #1 { TF } { \tl_if_single_token:nTF {#1} { \if_predicate:w \bool_if_p:n { \token_if_cs_p:N #1 || \token_if_active_p:N #1 } \prg_return_true: \else: \prg_return_false: \fi: } { \prg_return_false: } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\DeclareUTFcharacter} % 定义编码 |#1| 下的符号命令 |#3|,其对应符号的 Unicode 是 |#2|。 % \begin{macrocode} \RenewDocumentCommand \DeclareUTFcharacter { O { \UTFencname } m m } { \@@_if_csname:nTF {#3} { \@@_declare_character:Nnn #3 } { \exp_args:Nc \@@_declare_character:Nnn { \tl_to_str:n {#3} } } {#1} {#2} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_declare_character:Nnn} % 通过 \texttt{lowercase} 技巧,直接由 Unicode |#3| 得到编码 |#2| 下的符号命令 % |#1| 对应的实际字符。 % \begin{macrocode} \cs_new_protected:Npn \@@_declare_character:Nnn #1#2#3 { \@@_provide_text_command_default:N #1 \group_begin: \char_set_lccode:nn { `0 } { \@@_check_slot:n {#3} } \tl_to_lowercase:n { \group_end: \@@_declare_character:NNxn 0 } #1 { \token_to_str:N #1 } {#2} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_provide_text_command_default:N} % 如果控制序列 |#1| 已经存在,但不是符号命令,\pkg{xunicode} 会将它定义为 % \cs{UTFencname} 编码下的符号命令。但是编码被转换之后,再使用这些控制序列, % \pkg{NFSS} 就会报错。为此需要给出这些符号命令的默认定义,与原来的意义相同。 % 这些命令包括 % \begin{verbatim} % \nobreakspace macro:->\protect \nobreakspace % \copyright macro:->\protect \copyright % \AA macro:->\r A % \aa macro:->\r a % \textrhookopeno \long macro:->\textrethookbelow {\textopeno } % \hbar macro:->{\mathchar '26\mkern -9muh} % \textaolig macro:->{a\kern -.25em o} % \end{verbatim} % 影响比较大的是 \cs{nobreakspace}、\cs{copyright} 和 \cs{hbar}。 % \begin{macrocode} \cs_new_protected:Npn \@@_provide_text_command_default:N #1 { \bool_if:nF { \cs_if_exist_p:c { ? \token_to_str:N #1 } || \cs_if_free_p:c { ? - \token_to_str:N #1 } } { \exp_args:NNv \ProvideTextCommandDefault #1 { ? - \token_to_str:N #1 } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_declare_character:NNnn} % 使用编码 |#4| 下的符号命令 |#2| 的时候先判断它对应的实际字符 |#1| 在当前字体中 % 是否存在。如果不存在则转换到 \cs{DeclareTextSymbolDefault} 中设置的编码或者使用 % \cs{Declare\-Text\-Command\-Default} 中设置的命令。 % \begin{macrocode} \cs_new_protected:Npn \@@_declare_character:NNnn #1#2#3#4 { \DeclareTextCommand #2 {#4} { \@@_text_character:nN {#3} {#1} } } \cs_new_protected:Npn \@@_text_character:nN #1#2 { \tl_use:N \l_@@_begin_hook_tl \@@_glyph_if_exist:nTF { `#2 } {#2} { \cs_if_exist_use:cF { ? #1 } {#2} } \tl_use:N \l_@@_end_hook_tl } \cs_generate_variant:Nn \@@_declare_character:NNnn { NNx } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_check_slot:n} % \pkg{xunicode} 中使用的 Unicode 格式是诸如 |x0022| 的形式,这就需要一些转换。 % \begin{macrocode} \cs_new_nopar:Npn \@@_check_slot:n #1 { \int_eval:n { \tl_if_head_eq_charcode:nNTF {#1} x { " \use_none:n #1 } {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\DeclareUTFcomposite} % 设置编码 |#1| 下的符号命令 |#3| 与它的参数 |#4| 的复合对应的符号的 Unicode 是 |#2|。 % \begin{macrocode} \RenewDocumentCommand \DeclareUTFcomposite { O { \UTFencname } m m m } { \@@_if_csname:nTF {#3} { \@@_declare_composite:Nnnn #3 } { \exp_args:Nc \@@_declare_composite:Nnnn { \tl_to_str:n {#3} } } {#1} {#4} {#2} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_declare_composite:Nnnn} % 这里使用 \cs{tex_afterassignment:D} 是因为 \pkg{xunicode} 有如下的定义。 % \begin{verbatim} % \DeclareUTFcomposite[\UTFencname]{x02E8\char"02E5}{\tonebar}{25} % \DeclareUTFcomposite[\UTFencname]{x02E5\char"02E8}{\tonebar}{52} % \end{verbatim} % 但是这个定义原本就是无效的,|\tonebar{25}| 和 |\tonebar{2}| 的定义一样。 % 对复合符号命令的定义用的是 \cs{chardef},这有利于下面字符是否存在的判断。 % \begin{macrocode} \cs_new_protected:Npn \@@_declare_composite:Nnnn #1#2#3#4 { \tex_afterassignment:D \use_none_delimit_by_q_stop:w \@@_chardef:cn { \token_to_str:c {#2} \token_to_str:N #1 - \tl_to_str:n {#3} } { \@@_check_slot:n {#4} } \q_stop } \cs_new_protected:Npn \@@_chardef:Nn #1#2 { \tex_chardef:D #1 = \etex_numexpr:D #2 \scan_stop: } \cs_generate_variant:Nn \@@_chardef:Nn { c } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\DeclareEncodedCompositeCharacter} % |#1| 是编码,|#2| 是重音命令,|#3| 是组合重音符号的 Unicode,|#4| 是基本重音符号 % 的 Unicode。当 |#2| 的参数为空时,输出 |#4|,否则是 |#2| 与 |#3| 的组合。 % \begin{macrocode} \RenewDocumentCommand \DeclareEncodedCompositeCharacter { m m m m } { \@@_if_csname:nTF {#2} { \@@_declare_accent:Nnnn #2 } { \exp_args:Nc \@@_declare_accent:Nnnn { \tl_to_str:n {#2} } } {#1} {#3} {#4} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\DeclareEncodedCompositeAccents} % |#1| 是编码,|#2| 是重音命令,|#3| 和 |#4| 都是组合重音的 Unicode。当 |#2| 的 % 参数为空时,输出 |#3|,否则是 |#2| 与 |#4| 的组合。 % \begin{macrocode} \RenewDocumentCommand \DeclareEncodedCompositeAccents { m m m m } { \@@_if_csname:nTF {#2} { \@@_declare_accent:Nnnn #2 } { \exp_args:Nc \@@_declare_accent:Nnnn { \tl_to_str:n {#2} } } {#1} {#4} {#3} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_declare_accent:Nnnn} % 通过 \texttt{lowercase} 技巧,直接由重音符号的 Unicode 得到实际字符。 % \begin{macrocode} \cs_new_protected:Npn \@@_declare_accent:Nnnn #1#2#3#4 { \group_begin: \char_set_lccode:nn { `3 } { "#3 } \char_set_lccode:nn { `4 } { \tl_if_blank:nTF {#4} { "#3 } { "#4 } } \tl_to_lowercase:n { \group_end: \@@_declare_accent:NNNxxn 3 4 } #1 { \token_to_str:c {#2} } { \token_to_str:N #1 } {#2} } \cs_new_protected:Npn \@@_declare_accent:NNNnnn #1#2#3#4#5#6 { \DeclareTextCommand #3 {#6} { \@@_text_composite:nnNNn {#4} {#5} {#1} {#2} } } \cs_generate_variant:Nn \@@_declare_accent:NNNnnn { NNNxx } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_text_composite:nnNNn} % 若重音命令 |#2| 与它的参数 |#5| 的复合已经由 \cs{DeclareUTFcomposite} 设置, % 并且在当前字体中存在该字符,则直接使用。否则使用组合命令。 % \begin{macrocode} \cs_new_protected:Npn \@@_text_composite:nnNNn #1#2#3#4#5 { \tl_use:N \l_@@_begin_hook_tl \cs_if_exist:cTF { #1#2 - \tl_to_str:n {#5} } { \token_if_chardef:cTF { #1#2 - \tl_to_str:n {#5} } { \@@_glyph_if_exist:nTF { \use:c { #1#2 - \tl_to_str:n {#5} } } { \use:c { #1#2 - \tl_to_str:n {#5} } } { \@@_add_accent:nnNN {#5} {#2} #3#4 } } { \use:c { #1#2 - \tl_to_str:n {#5} } } } { \@@_add_accent:nnNN {#5} {#2} #3#4 } \tl_use:N \l_@@_end_hook_tl } \cs_generate_variant:Nn \token_if_chardef:NTF { c } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_add_accent:nnNN} % 若组合重音符号的 |#3| 和基本重音符号 |#4| 在当前字体中都不存在,则转换到 % \cs{Declare\-Text\-Accent\-Default} 设置的编码或者使用 % \cs{DeclareTextCommandDefault} 中设置的命令。\texttt{0.9999} 版以前的 \XeTeX % 需要设置 \cs{XeTeXinputnormalization} 为 $1$,才能使用字体中由基础字符和组合符号 % 对应的实际字符;而 \texttt{0.9999} 版以后的 \XeTeX 默认就启用这个功能,^^A % \cs{XeTeXinputnormalization} 似乎是无效的,怀疑是使用 HarfBuzz 库替代 ICU 进行 % 字体排版的缘故\footnote{\url{http://tug.org/pipermail/xetex/2013-July/024579.html}}。 % \begin{macrocode} \cs_new_protected:Npn \@@_add_accent:nnNN #1#2#3#4 { \tl_if_blank:nTF {#1} { \@@_glyph_if_exist:nTF { `#4 } {#4} { \cs_if_exist_use:cTF { ? #2 } { {#1} } {#4} } } { \@@_glyph_if_exist:nTF { `#3 } { #1#3 } { \@@_glyph_if_exist:nTF { `#4 } { \add@accent { `#4 } {#1} } { \cs_if_exist_use:cTF { ? #2 } { {#1} } {#1} } } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\AtBeginUTFCommand,\AtEndUTFCommand} % 在符号命令前后使用的钩子。 % \begin{macrocode} \NewDocumentCommand \AtBeginUTFCommand { s +m } { \IfBooleanTF {#1} { \tl_set:Nn \l_@@_begin_hook_tl {#2} } { \tl_put_right:Nn \l_@@_begin_hook_tl {#2} } } \NewDocumentCommand \AtEndUTFCommand { s +m } { \IfBooleanTF {#1} { \tl_set:Nn \l_@@_end_hook_tl {#2} } { \tl_put_right:Nn \l_@@_end_hook_tl {#2} } } \tl_new:N \l_@@_begin_hook_tl \tl_new:N \l_@@_end_hook_tl % \end{macrocode} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % % \setbox\xeCJKtmpbox\vbox\bgroup\gobblelineno % \begin{macrocode} %<@@=xeCJK> % \end{macrocode}\egroup % % \subsection{\pkg{xeCJK.cfg}} % % \begin{macrocode} %<*config> % \end{macrocode} % % 预设的配置文件 \file{xeCJK.cfg} 为一个空文件。可以在里面增加设置,然后保存到 % 本地目录下面。 % \begin{macrocode} % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % \iffalse % % \makeatletter % \let\special@index\@gobble % \makeatother % % \section{例子} % % \subsection{\pkg{xeCJK-example-autofake.tex}} % % \begin{macrocode} %<*ex-autofake> % \end{macrocode} % % \begin{macrocode} \documentclass{article} \usepackage[AutoFakeBold,AutoFakeSlant]{xeCJK} \setCJKmainfont[BoldFont=simhei.ttf, ItalicFont=simkai.ttf]{simsun.ttc} \setCJKsansfont[AutoFakeSlant=false, BoldFont=simhei.ttf, ItalicFont=simkai.ttf]{simsun.ttc} \setCJKmonofont[ItalicFont=simkai.ttf]{simsun.ttc} \begin{document} \centering \begin{tabular}{lllll} \hline {\bf rm} & md & up & \verb|\rmfamily\mdseries\upshape| & {\rmfamily\mdseries\upshape English 中文字体} \\ & md & it & \verb|\rmfamily\mdseries\itshape| & {\rmfamily\mdseries\itshape English 中文字体} \\ & md & sl & \verb|\rmfamily\mdseries\slshape| & {\rmfamily\mdseries\slshape English 中文字体} \\ \cline{2-5} & bf & up & \verb|\rmfamily\bfseries\upshape| & {\rmfamily\bfseries\upshape English 中文字体} \\ & bf & it & \verb|\rmfamily\bfseries\itshape| & {\rmfamily\bfseries\itshape English 中文字体} \\ & bf & sl & \verb|\rmfamily\bfseries\slshape| & {\rmfamily\bfseries\slshape English 中文字体} \\ \hline {\bf sf} & md & up & \verb|\sffamily\mdseries\upshape| & {\sffamily\mdseries\upshape English 中文字体} \\ & md & it & \verb|\sffamily\mdseries\itshape| & {\sffamily\mdseries\itshape English 中文字体} \\ & md & sl & \verb|\sffamily\mdseries\slshape| & {\sffamily\mdseries\slshape English 中文字体} \\ \cline{2-5} & bf & up & \verb|\sffamily\bfseries\upshape| & {\sffamily\bfseries\upshape English 中文字体} \\ & bf & it & \verb|\sffamily\bfseries\itshape| & {\sffamily\bfseries\itshape English 中文字体} \\ & bf & sl & \verb|\sffamily\bfseries\slshape| & {\sffamily\bfseries\slshape English 中文字体} \\ \hline {\bf tt} & md & up & \verb|\ttfamily\mdseries\upshape| & {\ttfamily\mdseries\upshape English 中文字体} \\ & md & it & \verb|\ttfamily\mdseries\itshape| & {\ttfamily\mdseries\itshape English 中文字体} \\ & md & sl & \verb|\ttfamily\mdseries\slshape| & {\ttfamily\mdseries\slshape English 中文字体} \\ \cline{2-5} & bf & up & \verb|\ttfamily\bfseries\upshape| & {\ttfamily\bfseries\upshape English 中文字体} \\ & bf & it & \verb|\ttfamily\bfseries\itshape| & {\ttfamily\bfseries\itshape English 中文字体} \\ & bf & sl & \verb|\ttfamily\bfseries\slshape| & {\ttfamily\bfseries\slshape English 中文字体} \\ \hline \end{tabular} \end{document} % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % \subsection{\pkg{xeCJK-example-fallback.tex}} % % \begin{macrocode} %<*ex-fallback> % \end{macrocode} % % \begin{macrocode} \documentclass{article} \usepackage[AutoFallBack]{xeCJK} \usepackage{xeCJKfntef} \usepackage{array} \setCJKmainfont[AutoFakeBold,AutoFakeSlant]{KaiTi_GB2312} \setCJKfallbackfamilyfont{\CJKrmdefault}[BoldFont=SimHei] { [SlantedFont=FangSong]{SimSun} , [BoldFont=*] {SimSun-ExtB} } \begin{document} 漢字源𣴑考 \textbf{漢字源𣴑考} \textsl{漢字源𣴑考} \CJKunderwave{漢字源𣴑考} \begin{table}[ht] \caption{生僻字测试} \medskip\centering \begin{tabular}{*4{|c>{\ttfamily U+}l}|} 㐀 & 3400 & 㐁 & 3401 & 㐂 & 3402 & 㐃 & 3403 \\ 㐄 & 3404 & 㐅 & 3405 & 㐆 & 3406 & 㐇 & 3407 \\ 㐈 & 3408 & 㐉 & 3409 & 㐊 & 340A & 㐋 & 340B \\ 㐌 & 340C & 㐍 & 340D & 㐎 & 340E & 㐏 & 341F \\ 㐐 & 3410 & 㐑 & 3411 & 㐒 & 3412 & 㐓 & 3413 \\ 㐔 & 3414 & 㐕 & 3415 & 㐖 & 3416 & 㐗 & 3417 \\ 㐘 & 3418 & 㐙 & 3419 & 㐚 & 341A & 㐛 & 341B \\ 㐜 & 341C & 㐝 & 341D & 㐞 & 341E & 㐟 & 341F \\[1ex] 𠀀 & 20000 & 𠀁 & 20001 & 𠀂 & 20002 & 𠀃 & 20003 \\ 𠀄 & 20004 & 𠀅 & 20005 & 𠀆 & 20006 & 𠀇 & 20007 \\ 𠀈 & 20008 & 𠀉 & 20009 & 𠀊 & 2000A & 𠀋 & 2000B \\ 𠀌 & 2000C & 𠀍 & 2000D & 𠀎 & 2000E & 𠀏 & 2000F \\ 𠀐 & 20010 & 𠀑 & 20011 & 𠀒 & 20012 & 𠀓 & 20013 \\ 𠀔 & 20014 & 𠀕 & 20015 & 𠀖 & 20016 & 𠀗 & 20017 \\ 𠀘 & 20018 & 𠀙 & 20019 & 𠀚 & 2001A & 𠀛 & 2001B \\ 𠀜 & 2001C & 𠀝 & 2001D & 𠀞 & 2001E & 𠀟 & 2001F \\ \end{tabular} \end{table} \end{document} % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % \subsection{\pkg{xeCJK-example-subCJKblock.tex}} % % \begin{macrocode} %<*ex-block> % \end{macrocode} % % \begin{macrocode} \documentclass{article} \usepackage{xeCJK} \usepackage{array} \xeCJKDeclareSubCJKBlock{Ext-A} { "3400 -> "4DBF } \xeCJKDeclareSubCJKBlock{Ext-B} { "20000 -> "2A6DF } \xeCJKDeclareSubCJKBlock{Kana} { "3040 -> "309F, "30A0 -> "30FF, "31F0 -> "31FF, } \xeCJKDeclareSubCJKBlock{Hangul}{ "1100 -> "11FF, "3130 -> "318F, "A960 -> "A97F, "AC00 -> "D7AF } \setCJKmainfont[Ext-A=SimHei,Ext-B=SimSun-ExtB]{SimSun} \setCJKmainfont[Kana]{Meiryo} \setCJKmainfont[Hangul]{Malgun Gothic} \parindent=2em \begin{document} \long\def\showtext{% 中日韩越统一表意文字(英语:CJKV Unified Ideographs),旧称中日韩统一表意文字(英语:CJK Unified Ideographs),也称统一汉字(英语:Unihan),目的是要把分别来自中文、日文、韩文、越文、壮文中,对于相同起源、本义相同、形状一样或稍异的表意文字(主要为汉字,但也有仿汉字如:方块壮字、日文汉字(かんじ / kanji)、韩文汉字(한자 / hanja)、越南的喃字(Chữ Nôm)与越文汉字(Chữ Nho,在越南也称作儒字),应赋予其在ISO 10646及统一码标准中有相同编码。此计划原本只包含中文、日文及韩文中所使用的汉字,是以旧称中日韩统一表意文字(CJK)。后来,此计划加入了越文的喃字,所以合称中日韩越统一表意文字(CJKV)。 CJK統合漢字(シージェーケーとうごうかんじ、CJK Unified Ideographs)は、ISO/IEC 10646 (Universal Multiple-Octet Coded Character Set, 略称 UCS) および Unicodeにて採用されている符号化用漢字集合およびその符号表である。CJK統合漢字の名称は、中国語(Chinese)、日本語(Japanese)、韓国語(Korean)で使われている漢字をひとまとめにしたことからきている。CJK統合漢字の初版である Unified Repertoire and Ordering (URO) 第二版は1992年に制定されたが、1994年にベトナムで使われていた漢字も含めることにしたため、CJKVと呼ばれる事もある。CJKVは、中国語・日本語・韓国語・ベトナム語 (英語: Chinese-Japanese-Korean-Vietnamese) の略。特に、その4言語で共通して使われる、または使われていた文字体系である漢字(チュノムを含む)のこと。ソフトウェアの国際化、中でも文字コードに関する分野で用いられる。 \CJKspace 한중일월 통합 한자(또는 한중일 통합 한자)는 유니코드에 담겨 있는 한자들의 집합으로, 한국, 중국, 일본에서 쓰이는 한자를 묶은 것이기 때문에 머리 글자를 따서 한중일(CJK) 통합 한자라고 불렀는데, 최근에는 베트남에서 쓰이는 한자도 추가되었기에 한중일월(CJKV) 통합 한자로 부르게 되었다. 처음에 유니코드에는 65,536($=2^{16}$)자만 들어갈 수 있었기 때문에, 가장 많은 문자가 배당되는 한자를 위해서 한국, 중국, 일본에서 사용하는 한자 중에 모양이 유사하며 그 뜻이 같은 글자를 같은 코드로 통합했다. 따라서 문자 코드만으로 그 한자가 사용되는 언어를 알아 낼 수 없는데, 다만 중국의 간체자나 번체자, 일본의 구자체나 신자체 등 분명하게 모양이 다른 글자는 별도의 부호를 할당하고 있다. 이런 문자 할당 정책에 반발하여 TRON과 같은 인코딩이 만들어지기도 했으나, 실제로 통합된 한자의 차이가 별로 크지 않기 때문에 문제가 되지 않는다는 의견도 있다. \CJKnospace} \showtext \bigskip \xeCJKCancelSubCJKBlock{Kana,Hangul} \showtext \bigskip \xeCJKRestoreSubCJKBlock{Hangul} \showtext \begin{table}[ht] \caption{生僻字测试} \medskip\centering \begin{tabular}{*4{|c>{\ttfamily U+}l}|} 㐀 & 3400 & 㐁 & 3401 & 㐂 & 3402 & 㐃 & 3403 \\ 㐄 & 3404 & 㐅 & 3405 & 㐆 & 3406 & 㐇 & 3407 \\ 㐈 & 3408 & 㐉 & 3409 & 㐊 & 340A & 㐋 & 340B \\ 㐌 & 340C & 㐍 & 340D & 㐎 & 340E & 㐏 & 341F \\ 㐐 & 3410 & 㐑 & 3411 & 㐒 & 3412 & 㐓 & 3413 \\ 㐔 & 3414 & 㐕 & 3415 & 㐖 & 3416 & 㐗 & 3417 \\ 㐘 & 3418 & 㐙 & 3419 & 㐚 & 341A & 㐛 & 341B \\ 㐜 & 341C & 㐝 & 341D & 㐞 & 341E & 㐟 & 341F \\[1ex] 𠀀 & 20000 & 𠀁 & 20001 & 𠀂 & 20002 & 𠀃 & 20003 \\ 𠀄 & 20004 & 𠀅 & 20005 & 𠀆 & 20006 & 𠀇 & 20007 \\ 𠀈 & 20008 & 𠀉 & 20009 & 𠀊 & 2000A & 𠀋 & 2000B \\ 𠀌 & 2000C & 𠀍 & 2000D & 𠀎 & 2000E & 𠀏 & 2000F \\ 𠀐 & 20010 & 𠀑 & 20011 & 𠀒 & 20012 & 𠀓 & 20013 \\ 𠀔 & 20014 & 𠀕 & 20015 & 𠀖 & 20016 & 𠀗 & 20017 \\ 𠀘 & 20018 & 𠀙 & 20019 & 𠀚 & 2001A & 𠀛 & 2001B \\ 𠀜 & 2001C & 𠀝 & 2001D & 𠀞 & 2001E & 𠀟 & 2001F \\ \end{tabular} \end{table} \end{document} % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % % \subsection{\pkg{xeCJK-example-CJKecglue.tex}} % % \begin{macrocode} %<*ex-ecglue> % \end{macrocode} % % \begin{macrocode} \documentclass{minimal} \usepackage{xeCJK} \setCJKmainfont[BoldFont=SimHei]{SimSun} \long\def\showtext{% 这是 English 中文 {\itshape Chinese} 中文 \TeX\ 间隔 \textit{Italic} 中文\textbf{字体} a 数学 $b$ 数学 $c$ $d$\par 这是English中文{\itshape Chinese}中文\TeX\ 间隔\textit{Italic}中文\textbf{字体}a数学$b$数学$c$ $d$\par This is an example. 这是一个例子} \begin{document} \showtext \hrulefill\bigskip \xeCJKsetup{xCJKecglue=\quad} \showtext \end{document} % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % \subsection{\pkg{xeCJK-example-checksingle.tex}} % % \begin{macrocode} %<*ex-single> % \end{macrocode} % % \begin{macrocode} \documentclass{minimal} \usepackage{xeCJK} \setCJKmainfont{SimSun} \catcode`\。=\active \def。{.} \def\foo{一} \long\def\showtext{一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十。 \[x^2+y^2\] 一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十\foo $$x^2+y^2$$ 一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十\foo \begin{equation} x^2+y^2 \end{equation} 一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十。} \begin{document} \hsize=30em \parindent=0pt \showtext \hrulefill\bigskip \xeCJKsetup{CheckSingle} \showtext \hrulefill\bigskip \xeCJKsetup{PlainEquation} \showtext \end{document} % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % \subsection{\pkg{xeCJK-example-CJKfntef.tex}} % % \begin{macrocode} %<*ex-fntef> % \end{macrocode} % % \begin{macrocode} \documentclass{ctexart} \usepackage{xcolor} \usepackage{xeCJKfntef} \xeCJKDeclareSubCJKBlock{test}{ `殆 , `已 } \setCJKmainfont[test=SimHei]{SimSun} \def\showtext{% 庄子曰:“吾生也有涯,而知也无涯。以有涯随无涯,殆已!已而为知者,殆而已矣!% 为善无近名,为恶无近刑,缘督以为经,可以保身,可以全生,可以养亲,可以尽年。”} \newcommand\CJKfntef[1]{% \csname#1\endcsname{\showtext}\par \csname#1\endcsname*{\showtext}\par \CJKunderdot{\showtext\csname#1\endcsname{\showtext}}\par \CJKunderdot{\showtext\csname#1\endcsname*{\showtext}}\par \csname#1\endcsname{\showtext\CJKunderdot{\showtext}}\par \csname#1\endcsname*{\showtext\CJKunderdot{\showtext}}\par\bigskip} \begin{document} \section{\textsf{xeCJKfntef} 的简单测试文件} \CJKunderline{汉 字}\CJKunderline{加下划线} \varCJKunderline{汉字}\varCJKunderline{加下划线} \CJKunderanyline{0.5em}{\sixly \kern-.021em\char58 \kern-.021em}{自定义下划线} \CJKunderanyline{0.2em}{\kern-.03em\vtop{\kern.2ex\hrule width.2em\kern 0.11em \hrule height 0.1em}\kern-.03em}{自定义下划线} \indent\CJKunderanyline{0.5em}{-}{\showtext} \CJKunderanysymbol{0.2em}{-}{\showtext} \CJKunderdot{\showtext} \hrule depth \dp\strutbox width 0 pt \relax \begin{CJKfilltwosides}{40mm} 两端分散对齐\\ 分散对齐\\ \CJKunderdot{汉字可加点}\\ \CJKunderline{汉字可加下划线} \end{CJKfilltwosides} \hrule depth \dp\strutbox width 0 pt \relax \CJKfntef{CJKunderline} \CJKfntef{CJKunderwave} \CJKfntef{CJKunderdblline} \CJKfntef{CJKsout} \CJKfntef{CJKxout} \end{document} % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % \subsection{\pkg{xeCJK-example-punctstyle.tex}} % % \begin{macrocode} %<*ex-punctstyle> % \end{macrocode} % % \begin{macrocode} \documentclass{article} \usepackage{xeCJK} \setCJKmainfont{SimSun} \xeCJKDeclarePunctStyle { mine } { fixed-punct-ratio = 0 , fixed-margin-width = 0 pt , mixed-margin-width = \maxdimen , mixed-margin-ratio = 0.5 , middle-margin-width = \maxdimen , middle-margin-ratio = 0.5 , add-min-bound-to-margin = true , min-bound-to-kerning = true , kerning-margin-minimum = 0.1 em } \begin{document} \setlength\parindent{2em} \newcommand\showexample[1]{% \texttt{------ #1 ------}\par\xeCJKsetup{PunctStyle=#1}\showtexts\par} \newcommand\showtexts{% 列位看官:你道此书从何而来?说起根由,虽近荒唐,细按则深有趣味。待在下将此来历注明,方使阅者了然不惑。 原来女娲氏炼石补天之时,于大荒山无稽崖炼成高经十二丈、方经二十四丈顽石三万六千五百零一块。娲皇氏只用了三万六千五百块,只单单剩了一块未用,便弃在此山青埂峰下。谁知此石自经煆炼之后,灵性已通,因见众石俱得补天,独自己无材不堪入选,遂自怨自叹,日夜悲号惭愧。 一日,正当嗟悼之际,俄见一僧一道远远而来,生得骨格不凡,丰神迥别,说说笑笑,来至峰下,坐于石边,高谈快论:先是说些云山雾海、神仙玄幻之事,后便说到红尘中荣华富贵。此石听了,不觉打动凡心,也想要到人间去享一享这荣华富贵,但自恨粗蠢,不得已,便口吐人言,向那僧道说道:“大师,弟子蠢物,不能见礼了!适闻二位谈那人世间荣耀繁华,心切慕之。弟子质虽粗蠢,性却稍通,况见二师仙形道体,定非凡品,必有补天济世之材,利物济人之德。如蒙发一点慈心,携带弟子得入红尘,在那富贵场中,温柔乡里受享几年,自当永佩洪恩,万劫不忘也!”二仙师听毕,齐憨笑道:“善哉,善哉!那红尘中有却有些乐事,但不能永远依恃;况又有‘美中不足,好事多磨’八个字紧相连属,瞬息间则又乐极悲生,人非物换,究竟是到头一梦,万境归空,倒不如不去的好。”这石凡心已炽,那里听得进这话去,乃复苦求再四。二仙知不可强制,乃叹道:“此亦静极思动,无中生有之数也!既如此,我们便携你去受享受享,只是到不得意时,切莫后悔!”石道:“自然,自然。”那僧又道:“若说你性灵,却又如此质蠢,并更无奇贵之处。如此也只好踮脚而已。也罢!我如今大施佛法,助你助,待劫终之日,复还本质,以了此案。你道好否?”石头听了,感谢不尽。那僧便念咒书符,大展幻术,将一块大石登时变成一块鲜明莹洁的美玉,且又缩成扇坠大小的可佩可拿。那僧托于掌上,笑道:“形体倒也是个宝物了!还只没有实在的好处,须得再镌上数字,使人一见便知是奇物方妙。然后好携你到那昌明隆盛之邦、诗礼簪缨之族、花柳繁华地、温柔富贵乡去安身乐业。”石头听了,喜不能禁,乃问:“不知赐了弟子那哪几件奇处?又不知携了弟子到何地方?望乞明示,使弟子不惑。”那僧笑道:“你且莫问,日后自然明白的。”说着,便袖了这石,同那道人飘然而去,竟不知投奔何方何舍。 \hfill ——曹雪芹《红楼梦》} \showexample{mine} \showexample{quanjiao} \showexample{banjiao} \showexample{CCT} \showexample{kaiming} \showexample{hangmobanjiao} \showexample{plain} \end{document} % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % \subsection{\pkg{xeCJK-example-verbatim.tex}} % % \begin{macrocode} %<*ex-verb> % \end{macrocode} % % \begin{macrocode} \documentclass[a4paper]{article} \usepackage{xeCJK} \usepackage{fullpage} \xeCJKDeclareSubCJKBlock{Hangul} { "1100 -> "11FF, "3130 -> "318F, "A960 -> "A97F, "AC00 -> "D7AF } \setCJKmainfont{Adobe Song Std} \setCJKmainfont[Hangul]{Adobe Myungjo Std} %%\setmonofont{Inconsolata} %%\setmonofont{Source Code Pro} %%\setCJKmonofont{Adobe Kaiti Std} \setmonofont{TeX Gyre Cursor} \setCJKmonofont{Adobe Fangsong Std} \begin{document} \begin{verbatim} ************************************************************* * * * 精致甲版红楼梦 - 精致工作室特别奉献(2010年9月) * * * * GBK简体、GBK繁体、Big5繁体、PDF简体、PDF繁体 * * * * 为 GBK、Big5 特别度身订制,并经反复修订,方便纯文本阅读 * * * * 精致甲、乙版红楼梦下载专页 * * http://www.speedy7.com/cn/stguru/gb2312/redmansions.htm * * http://www.speedy7.com/cn/stguru/big5/redmansions.htm * * * * 此电子文件可随意传播、发布、下载。 * * 传播时建议保留此版本说明供查阅与识别。 * * 未经修订者同意,不得将此版本用于商业用途。 * * 如您对红楼梦不具深入了解,请勿随便修改其中的内容。 * * * ************************************************************* \end{verbatim} \verb|a 汉 字 b| \verb*|a 汉 字 b| \begin{verbatim} lang_set = { ["English"] = lang.en, ["Français"] = lang.fr, ["Español"] = lang.es, ["中文"] = lang.zh, ["日本語"] = lang.ja, ["한국어"] = lang.ko, } \end{verbatim} \end{document} % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % \subsection{\pkg{xeCJK-example-IVS.tex}} % % \begin{macrocode} %<*ex-IVS> % \end{macrocode} % % \begin{macrocode} \documentclass{article} \usepackage{xeCJK} \usepackage{hologo} \setCJKmainfont{HanaMinA} %% http://fonts.jp/hanazono/ \begin{document} \hologo{XeTeX} でIVSを使うテスト。 消󠄀化󠄀器󠄂 / 消󠄁火器󠄃 / 消󠄂化󠄁器󠄄 消󠄃火器󠄅 / 消化󠄂器󠄆 / 消火器󠄇 消化󠄃器󠄈 / 消火器󠄉 / 辻󠄂辻󠄃辻󠄄辻󠄅  \CJKfontspec{Meiryo} か がか゚ ぼぽ ぼぽ ばぱ ばぱ \end{document} % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % \subsection{\pkg{xeCJK-example-listings.tex}} % % \begin{macrocode} %<*ex-listings> % \end{macrocode} % % \begin{macrocode} \documentclass{article} \usepackage[margin=1in]{geometry} \usepackage{listings,xcolor} \usepackage{showexpl} \usepackage{xeCJK} \setCJKmainfont{HanaMinA} \setCJKmonofont{SimSun} \xeCJKDeclareSubCJKBlock{Kana} { "3040 -> "309F, "30A0 -> "30FF, "31F0 -> "31FF } \setCJKmonofont[Kana]{Meiryo} \setmonofont{Latin Modern Mono Light} \makeatletter \lstset{% basicstyle=\small\ttfamily,breakindent=4\lst@width, numbers=left,numberstyle=\tiny\color{gray}, commentstyle=\color{green!50!black},keywordstyle=\color{blue}\bfseries, identifierstyle=\color{violet},stringstyle=\color{brown}, escapebegin=\normalfont} \lstnewenvironment{cppcode}[1][] {\lstset{language=C++,#1}} {} \makeatother \begin{document} \section{\lstinline{\\lstinline} 测试} \section{\lstinline|甲*乙| 测试} \lstinline|abc汉字abc| \lstinline|甲*乙| \lstinline[mathescape]|数学公式$x^2+y^2$| \section{\lstinline{lstlisting} 环境测试} \begin{lstlisting}[basicstyle=\rmfamily] 纯文字text测试 纯文字text测试 文字+文字 文字(符号)文字 辻󠄂辻󠄃辻󠄄辻󠄅 かがか゚ \end{lstlisting} \begin{lstlisting} text纯文字测试 \end{lstlisting} \begin{lstlisting} text 纯文字测试 \end{lstlisting} \begin{lstlisting} text,纯文字测试 \end{lstlisting} \section{自定义环境测试} \begin{LTXexample}[pos=t,varwidth,numbersep=5pt,columns=fixed] \begin{cppcode}[escapechar=`,morekeywords=返回] #define 返回 return #include /* * 块注释 * `逃逸字符,测试$f(x)$` */ int main() { // 行注释 const char *欢迎 = "hello 世界(ワールド)"; std::cout << 欢迎 << std::endl; 返回 0; } \end{cppcode} \end{LTXexample} \section{\texttt{breaklines} 测试} \begin{lstlisting}[linewidth=10em,frame=single,rulecolor=\color{black},breaklines] 断行文字text测试,断行文字text测试,断行文字text测试,断行文字text测试 断行文字text测试,断行文字text测试,断行文字text测试,断行文字text测试 \end{lstlisting} \section{\lstinline|\\lstinputlisting| 测试} \lstinputlisting[language={[AlLaTeX]TeX}]{\jobname} \end{document} % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % \fi % % \end{implementation} % % % \Finale % \endinput