Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

有办法使 xCJKecglue 随着字体而变化吗? #31

Closed
1 task done
RuixiZhang42 opened this issue May 11, 2019 · 6 comments
Closed
1 task done

有办法使 xCJKecglue 随着字体而变化吗? #31

RuixiZhang42 opened this issue May 11, 2019 · 6 comments

Comments

@RuixiZhang42
Copy link
Member

检查

  • 已在 issues 中进行搜索(包括已关闭的问题)

描述问题

通过 xeCJK 宏包提供的 xCJKecglue 选项,我们可以调整中西文之间空格的大小。美中不足的是,这个值通用于罗马(衬线)字族与无衬线字族的全部字体。我希望能够调整 xCJKecglue 的值,使得 xCJKecglue + 数字宽 + xCJKecglue 占一个汉字宽,这样 第一章第 1 章 就可以占据同样多的位置(不论是正体、意大利斜体,还是衬线、无衬线)。或许可以通过 NFSS 的某个钩子执行自定义的 \xeCJKsetup{ xCJKecglue = <glue> }

最小工作示例(MWE)

\documentclass{article}
\usepackage{xeCJK} % loads fontspec internally

\setmainfont{TeX Gyre Schola} % Latin fonts specification

% Regular and italic faces have digit width 556/1000
\xeCJKsetup{ xCJKecglue = {\hskip 0.222em plus 0.05em minus 0.05em\relax} }

% Bold and bold italic faces have digit width 574/1000
%\xeCJKsetup{ xCJKecglue = {\hskip 0.213em plus 0.05em minus 0.05em\relax} }

\begin{document}
\huge
\begin{tabular}{ll}
第一章\rule[-0.2em]{0.4pt}{1em} & \bfseries 第一章\rule[-0.2em]{0.4pt}{1em} \\
第1章\rule[-0.2em]{0.4pt}{1em} & \bfseries 第1章\rule[-0.2em]{0.4pt}{1em} \\
\end{tabular}
\end{document}

(用 XeLaTeX 编译后)输出

misaligned

链接

@qinglee
Copy link
Member

qinglee commented May 11, 2019

可以在 everysel 包提供的钩子中通过对 \f@series 进行判别来处理,一个简单的例子:

\documentclass{article}
\usepackage{xeCJK} % loads fontspec internally

\setmainfont{TeX Gyre Schola} % Latin fonts specification

\usepackage{everysel}

\makeatletter
\newcommand*\SETCJKECGLUE{%
  \ifcase\strcmp{\f@series}{\bfdefault} %
    \xeCJKsetup
      { xCJKecglue = {\hskip 0.213em plus 0.05em minus 0.05em\relax} }%
  \else
    \xeCJKsetup
      { xCJKecglue = {\hskip 0.222em plus 0.05em minus 0.05em\relax} }%
  \fi  
}
\EverySelectfont{\SETCJKECGLUE}
\makeatother

\begin{document}
\huge

第1章 \bfseries 第1章

\showoutput

\end{document}

差别很小:

....\TU/FandolSong-Regular(0)/m/n/20.74 第
....\glue 4.60428 plus 1.03705 minus 1.03705
....\TU/TeXGyreSchola(0)/m/n/20.74 1
....\glue 4.60428 plus 1.03705 minus 1.03705
....\TU/FandolSong-Regular(0)/m/n/20.74 章
....\glue 0.0 plus 2.00005
....\TU/FandolSong-Regular(0)/bx/n/20.74 第
....\glue 4.41756 plus 1.03705 minus 1.03705
....\TU/TeXGyreSchola(0)/bx/n/20.74 1
....\glue 4.41756 plus 1.03705 minus 1.03705
....\TU/FandolSong-Regular(0)/bx/n/20.74 章

@RuixiZhang42
Copy link
Member Author

@qinglee 感谢介绍的 everysel 包!我粗略搜索了一下 \strcmp,发现它并不是一个 LaTeX2e 的命令,还需请教一下它的用法——原问题的例子非常精简,实际应用中,可能会遇到字族字重形状一旦改变,tabular 数字的宽度就会改变。我想是不是可以将 \SETCJKECGLUE 扩充成下面这个样子:

\newcommand*\SETCJKECGLUE{%
  \ifcase\strcmp{\f@family}{\rmdefault} % 罗马/衬线字族
    \ifcase\strcmp{\f@series}{\mddefault} % 常规体字重
      \ifcase\strcmp{\f@shape}{\updefault} % 常规体直立体
        \xeCJKsetup{ xCJKecglue = <glue> }%
      \else % 常规体斜体
        \xeCJKsetup{ xCJKecglue = <glue> }%
      \fi
    \else % 粗体字重
      \ifcase\strcmp{\f@shape}{\updefault} % 粗体直立体
        \xeCJKsetup{ xCJKecglue = <glue> }%
      \else % 粗体斜体
        \xeCJKsetup{ xCJKecglue = <glue> }%
      \fi
    \fi
  \else
    \ifcase\strcmp{\f@family}{\sfdefault} % 无衬线字族
      % 重复罗马字族的代码,先区分常规体、粗体,再在各自内部分直立体、斜体
    \else % 等宽字族,都等宽了则不需要分字重、形状
      \xeCJKsetup{ xCJKecglue = <glue> }%
    \fi
  \fi
}

如果是 TG Termes、Heros、Cursor 这种经典搭配,只需要最外层判断字族 \f@family 即可。对于 TG Schola 这种粗体数字加宽的还是少见,因此判断字重放在第二层。目前还没遇到过字重相等的情况下,斜体数字与直立体数字不等宽的字体(tabular 数字),因此将它放在最里层,也希望永远用不到。不知这样设计是否合理?

@stone-zeng
Copy link
Member

stone-zeng commented May 11, 2019

\strcmp 是 XeTeX 提供的扩展,可以在 xetex-reference.pdf 中找到:

Compares the full expansion of the two token list arguments. Expands to zero if they are the same, less than one if the first argument sorts lower (lexicographically) than the second argument, and greater than one if vice versa.

@RuixiZhang42
Copy link
Member Author

@stone-zeng 看起来我的用法不对?另:“less than one if the first argument sorts lower (lexicographically)” 是否有误?因为 0 也是小于 1 的……

@RuixiZhang42
Copy link
Member Author

尝试了一下,的确可以用嵌套判断语句来针对字体调整间距。最外层应该对最可能变化的 \f@family 作判断,然后第二层是 \f@series,最内层是 \f@shape

需要注意的是像 图~\ref{fig:example} 展示了 这样的句子会出问题,前后两个空格均变成西文空格。可以考虑用 图\nobreak\CJKecglue\ref{fig:example}\CJKecglue 展示了 代替。以下例子设的值仅为夸大示意。

\documentclass{article}
\usepackage{xeCJK} % loads fontspec internally
\setmainfont{TeX Gyre Schola}
\setsansfont{TeX Gyre Adventor}
\setmonofont{TeX Gyre Cursor}

\makeatletter
\def\setCJKecglue@nnn#1#2#3{%
  \xeCJKsetup
    { xCJKecglue = {\hskip #1em plus #2em minus #3em\relax} }%
}
\newcommand*\setCJKecglue{%
  \ifnum\strcmp{\f@family}{\rmdefault}=0 %
    \ifnum\strcmp{\f@series}{\mddefault}=0 %
      \ifnum\strcmp{\f@shape}{\updefault}=0 %
        \setCJKecglue@nnn{0.09}{0.045}{0.03}%
      \else
        \setCJKecglue@nnn{0.5}{0.25}{0.167}%
      \fi
    \else
      \ifnum\strcmp{\f@shape}{\updefault}=0 %
        \setCJKecglue@nnn{1}{0.5}{0.333}%
      \else
        \setCJKecglue@nnn{1.5}{0.75}{0.5}%
      \fi
    \fi
  \else
    \ifnum\strcmp{\f@family}{\sfdefault}=0 %
      \ifnum\strcmp{\f@series}{\mddefault}=0 %
        \setCJKecglue@nnn{0.6}{0.3}{0.2}%
      \else
        \setCJKecglue@nnn{0.9}{0.45}{0.3}%
      \fi
    \else
      \setCJKecglue@nnn{0.2}{0.1}{0.067}%
    \fi
  \fi
}
\makeatother

\usepackage{everysel}
\EverySelectfont{\setCJKecglue}

\newcommand\test{%
  \begin{tabular}{llll}
  第1章 & \itshape 第1章 & \bfseries 第1章 & \bfseries\itshape 第1章 \\
  第 1 章 & \itshape 第 1 章 & \bfseries 第 1 章 & \bfseries\itshape 第 1 章 \\
  \end{tabular}%
}
\newcommand*\figref[1]{%\nobreak\CJKecglue\ref{#1}\CJKecglue\ignorespaces
}
\newcommand*\figrefatend[1]{%\nobreak\CJKecglue\ref{#1}\ignorespaces
}

\begin{document}
\LARGE    \test\par
\sffamily \test\par
\ttfamily \test\par
\rmfamily
\begin{figure}
\caption{A figure to be referenced.}\label{fig:example}
\end{figure}
Type ``1'': Figure~1 shows that\dots\par
图~1 展示了……(unbalanced spaces)\par\nobreak\CJKecglue1 展示了……(balanced spaces)\par
Use labels: Figure~\ref{fig:example} shows that\dots\par
图~\ref{fig:example} 展示了……(Latin spaces)\par
\figref{fig:example} 展示了……(correct spaces)\par
See Figure~\ref{fig:example}.\par\figref{fig:example}。(wrong space before full stop)\par\figrefatend{fig:example} 。(no space before full stop)
\end{document}

CJKecglue

@RuixiZhang42
Copy link
Member Author

发现 @qinglee 之前的思路有疏漏之处:

\documentclass{article}% ctexart 行为一致
\usepackage{xeCJK}

\makeatletter
\newcommand*\setCJKecglue{%
  \ifnum\strcmp{\f@family}{\rmdefault}=0 %
    \xeCJKsetup{xCJKecglue={\hskip1em\relax}}%
  \else
    \ifnum\strcmp{\f@family}{\sfdefault}=0 %
      \xeCJKsetup{xCJKecglue={\hskip4em\relax}}%
    \else
      \xeCJKsetup{xCJKecglue={\hskip10em\relax}}%
    \fi
  \fi
}
\makeatother

\usepackage{everysel}
\EverySelectfont{\setCJKecglue}

\begin{document}
中文English中文\par 中文 English 中文\par
中文\textrm{English}中文\par 中文 \textrm{English} 中文\par
中文\textsf{English}中文\par 中文 \textsf{English} 中文\par
中文\texttt{English}中文\par 中文 \texttt{English} 中文\par

\normalsize
中文English中文\par 中文 English 中文\par
中文\textrm{English}中文\par 中文 \textrm{English} 中文\par
中文\textsf{English}中文\par 中文 \textsf{English} 中文\par
中文\texttt{English}中文\par 中文 \texttt{English} 中文\par
\end{document}

problem

问题如下:

  1. 正文开始后,罗马字族的全角 xCJKecglue 仍未生效,articlectexart 皆如此。
  2. 无衬线字族、等宽字族通过 xCJKecglue 还回去的空格有点令人吃惊。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants