首先,我只对适用于 的解决方案感兴趣pdfLaTeX
,而不是仅适用于 的解决方案LuaLaTex
。
“狭隘”问题
首先,初步说明一下:一些软件包重新定义了\f@series
假设对于粗体系列字体:“标准值”为bx
,但如果例如我们加载newtxtext
,那么它就是b
。
我的问题是,如何以编程方式将宏设置为\f@series
为粗体文本的值。但有一个警告:该解决方案应该在插入某些其他宏时才能工作,这可能会或可能不会使事情变得复杂。现在让我描述一下这些其他宏。
解决方案应在何种环境下发挥作用
我有一个名为的宏,如果周围的文本为粗体,则\OptBm
它适用于数学表达式,并且\bm
没有如果周围的文本是不是大胆的。
更准确地说,\bm
如果周围的文字是不在文档的默认文本粗细中,如果周围的文本是在文档的默认文本粗细中。我的问题实际上是如何使宏真正应用,\bm
当且仅当周围的文本真正为粗体时;更多内容见下文。
这是一个包含我的宏的 MWE:
\documentclass{memoir}
\usepackage{newtxtext}
\usepackage{bm}
\makeatletter
\newcommand{\Fseries}{\f@series} % for easier access to the content of \f@series
\edef\CharBx{\f@series}
% this means that \CharBx will be the string returned by \f@series for
% the default weight of the document
\newcommand{\OptBm}[1]{\ifx\f@series\CharBx#1\else\bm{#1}\fi}
\makeatother
\begin{document}
\tableofcontents
\section{Case $\protect\OptBm{\alpha>1}$}
\noindent This is when the surrounding text is not bold: \Fseries\ $\OptBm{\alpha}$
\noindent
{\bfseries This is when the surrounding text is bold: \Fseries\ $\OptBm{\alpha}$}
Note that $\alpha>1$ is boldfaced in the section title, but not boldfaced in the Table of Contents.
\end{document}
这不是一个XY问题
您可能会抱怨,对于我想要的目的,使用命令的可选参数就足够了\section
。但有时这是不可能的:例如,在 下RevTex4-2
,这个可选参数被忽略(参见这个问题)。
因此,我的\OptBm
宏在以下四种情况下可能会有用:1. 数学表达式出现在章节标题中,2. 章节标题在文档正文中以粗体显示,3. 章节标题是不是在目录中以粗体显示,并且 4. 我们不能使用命令的可选参数\section
来单独指定进入目录的标题。
同样,所有这四种情况都有可能发生,例如,如果我们使用RevTex4-2
。
我想要宏做什么
回到我的宏。我承认,对于我此时实际需要做的事情,\OptBm
现在的宏已经足够了。不过,请耐心等待。
我所拥有的起初是这样的:我没有加载newtxtext
包,我的宏是
\edef\CharBx{bx}
\newcommand{\OptBm}[1]{\ifx\f@series\CharBx\bm{#1}\else#1\fi}
但是当我加载时newtxtext
,我发现\CharBx
必须将定义修改为\edef\CharBx{b}
。这很烦人,所以我想让 始终\CharBx
保留适当的字母。但无论我怎么尝试,都无法让它工作。例如,\edef\CharBx{\bfseries \f@series}
不起作用, 也不起作用{\bfseries\edef\CharBx{\f@series}}
,我尝试的其他任何方法也不起作用。
最后,我想出了 MWE 中的代码。但是,正如我所说,MWE 中的代码的作用是\bm
当且仅当周围的文本是不符合文档的默认文本粗细。但我希望它只在周围文本为粗体时才适用\bm
。如果除了粗体和中等之外还有其他权重,则这两个权重不等同。请注意,一般来说,不可能提前(即在加载文档前言之前)知道哪些权重可能可用;这完全取决于我们使用什么字体。
此外,我不知道该如何以编程方式将宏设置\f@series
为粗体文本的值。
概括
- 有没有办法解决我的“狭义问题”?它能在我的 MWE 背景下发挥作用吗?
- 如果我的狭隘问题没有解决方案,使得它仍然在我的 MWE 上下文中起作用,那么是否有不同的方式来编写宏,
\OptBm
使得它确实适用于\bm
当且仅当周围的文本是粗体时,即使我们事先不知道还有哪些其他可用的字体粗细?
答案1
如果你只想覆盖b
相对 m
然后
\def\extracted@font@series@aux#1#2\stop{#1}
\edef\extracted@font@series{\expandafter\extracted@font@series@aux\f@series?\stop}
可以完成这项工作:你将得到一个字母,然后你可以使用它来测试
\if b\extracted@font@series TRUE\else FALSE\fi
事情可能要复杂得多:您可能同时使用了多种文本和数学模式权重。因为siunitx
我需要涵盖所有这些内容,允许使用链接问题中列出的所有文本权重等。这是一个检查特殊情况(权重在m
但不在\f@series
)的问题,然后将找到的权重与数学版本进行匹配。当然,这可能涉及两个字母的权重。你只需要系统地工作。
答案2
回答狭义的问题
这个问题是,
我们如何定义一个宏来保存
\f@series
在文档中调用\bfseries
或时假定的值\textbf
?
即使我们不使用 LaTeX 的默认字体,该解决方案也必须有效。
这其实很简单:我们记录当前的值\f@series
,全球应用\bfseries
,记录 \f@series` 的值,然后全球将字体系列设置为原始值。换句话说,
\edef\DefaultSeries{\f@series}
\bfseries
\edef\DefaultBoldWeight{\f@series}
\fontseries{\DefaultSeries}\selectfont
所需信息存储在 中\DefaultBoldWeight
。
为了确保此过程能够正常工作,应将此代码放在后 \begin{document}
。如果将其放在序言中,那么对于某些包(尤其是newtxtext
),\DefaultBoldWeight
最终会被设置为错误值。更详细地说:首先请注意,如果我们不加载任何包,bx
LaTeX 将把 和 设置为选定的权重\bfseries
。1另一方面\textbf
,包和包都将和设置为选定的权重。现在,如果将上述代码放在序言中,那么对于包,最终会被错误地设置为。即使当我们使用该包时,无论上述代码是放在序言中还是文档正文中,最终都会正确设置为。newtxtext
Noto
b
\bfseries
\textbf
newtxtext
\DefaultBoldWeight
bx
Noto
\DefaultBoldWeight
b
1中还存储了值\bfdefault
。令人惊讶的是,如果我们不加载任何包,则为\bfdefault
,b
但\bfseries
并\textbf
选择权重bx
。请参阅这个问题\bfseries
. (另一方面,\textbf
总是选择相同的权重,因为后者是使用前者定义的;参见 Ulrike Fischer 对这个问题。
以下是 MWE:
\documentclass{article}
% \usepackage[sfdefault]{noto}
\usepackage{newtxtext}
%
\begin{document}
%
% Here is the relevant code:
%
\makeatletter
\edef\DefaultSeries{\f@series}
\bfseries
\edef\DefaultBoldWeight{\f@series}
\fontseries{\DefaultSeries}\selectfont
\makeatother
%
% let's check that it worked
%
\makeatletter
\noindent Then default text weight of the current document: \f@series\\
\textbf{The default bold weight of the current document: \f@series}\\
\makeatother
The weight stored in \verb|\DefaultBoldWeight|: \DefaultBoldWeight
%
\end{document}
\bm
“体重透明”问题的答案
问题是,
如何制作一个宏,
\bm
当周围的文本是粗体时它就会应用,但如果周围的文本不是粗体时它就不会应用?
为什么我们需要这个
请注意,在 中RevTeX4-2
,节(和小节)标题在正文中为粗体,但在目录中为正常粗细。现在假设节标题包含一些数学模式中的文本。我们可能会决定,当标题中的周围文本为粗体(就像在正文中一样)时,数学表达式也应为粗体。但是当周围文本不是粗体时,例如在目录中,我们希望数学表达式不是要大胆。
在常规 LaTeX 中,可以向 、 等命令添加可选参数\section
;\subsection
主要参数是将哪些内容放入正文中,可选参数是将哪些内容放入目录中。但RevTex4-2
忽略可选参数;请参阅这里。
一种解决方案是使用某种“重量透明\bm
”命令。
与前一个“狭义问题”的关系(以及缺乏关系)
我原本以为这个问题的答案会用到上面狭义问题的答案。然而,我不再这么认为了,因为我有时间思考约瑟夫·赖特的回答以及对该答案的评论中的讨论。
我的主要认识是这样的:完全主流有一个包
- 定义了几种字体粗细,可以说,为了达到“weight-transparent”命令的目的,这些字体都应该算作“粗体”
\bm
,并且 - 并非所有这些粗细都具有以 开头的字体系列值/描述符2
b
。
2对于给定的字体粗细,其字体系列值(或者描述符\fontseries
) 是我们应该作为选择该字体粗细的参数的东西。
就上述第 2 点而言,请注意标准描述符集(至少根据LaTeX 2ε 字体选择自 2021 年 3 月起,第 5 页)包括sb
(半粗体)、eb
(特粗体)和ub
(极粗体),以及bx
(粗体扩展)和sbx
(半粗体扩展)。事实上,请注意
(一)Noto
Sans 字体有以下几种粗体:b
、sb
、eb
、ub
;
(ii) 默认 LaTeX 字体支持的粗体之一是bx
;以及
(iii) 支持的粗体之一是kpfonts
是sbx
。
所以我们甚至不能假设描述符不超过两个字母组成。
因此,在没有关于将使用哪种字体的更多具体信息的情况下,“weight-transparent \bm
”命令应该假设字体为粗体,如果其描述符包含字母“b”。例如,可以使用 LaTeX 内核命令\in@
和来确定是否是这种情况\ifin@
。(如何确定一个字符串是否包含在另一个字符串中,将在下面讨论这里,这里, 和这里。
定义宏的三种方法
我将这个“重量透明\bm
”命令称为\WTbm
。这是一个可能的定义:
\def\WT@in@#1#2{\edef\WT@Aux@in@{\noexpand\in@{#1}{#2}}\WT@Aux@in@}
\DeclareRobustCommand{\WTbm}[1]{\WT@in@{b}{\f@series}\ifin@{\bm{#1}}\else{#1}\fi}
这是基于第一个解决方案这个答案当然,我们可以直接使用这个答案,就像这样:
\def\instring#1#2{TT\fi\begingroup
\edef\x{\endgroup\noexpand\in@{#1}{#2}}\x\ifin@}
\DeclareRobustCommand{\WTbm}[1]{\if\instring{b}{\f@series}{\bm{#1}}\else{#1}\fi}
这个定义非常巧妙和优雅,但是代价是它更难理解。
我们也可以适应这个答案,像这样:
\def\HalfOfIn@{\in@{b}}
\DeclareRobustCommand{\WTbm}[1]{\expandafter\HalfOfIn@\expandafter{\f@series}\ifin@ \bm{#1}\else #1\fi}
此外,我们还可以排除某些特定权重,以免将其计为粗体\WTbm
。例如,为了让描述符eb
为不是算作粗体,请执行以下操作:在上述任何定义中,将 替换为\bm{#1}
。{\def\excl{eb}\ifx\f@series\excl#1\else\bm{#1}\fi}
例如,
\def\WT@in@#1#2{\edef\WT@Aux@in@{\noexpand\in@{#1}{#2}}\WT@Aux@in@}
\DeclareRobustCommand{\WTbm}[1]{\WT@in@{b}{\f@series}\ifin@{
{\def\excl{eb}\ifx\f@series\excl#1\else\bm{#1}\fi}
}\else{#1}\fi}
数学家
\documentclass{report}
\usepackage[T1]{fontenc}
\usepackage[sfdefault]{noto} % because Noto Sans has four different bold weights
\usepackage{bm}
\usepackage[margin=1.5in]{geometry}
%
% This is the definition of the main command of interest, \WTbm
%
\makeatletter
\def\WT@in@#1#2{\edef\WT@Aux@in@{\noexpand\in@{#1}{#2}}\WT@Aux@in@}
\DeclareRobustCommand{\WTbm}[1]{\WT@in@{b}{\f@series}\ifin@{\bm{#1}}\else{#1}\fi}
\makeatother
%
% what follows is inessential
%
% for easier access to the content of \f@series
\makeatletter
\newcommand{\Fseries}{\f@series}
\makeatother
%
% for easy tyesetting of the names \Fseries and \WTbm
\newcommand{\FseriesName}{\texttt{\textbackslash{}f@series}}
\newcommand{\WTbmName}{\texttt{\textbackslash{}WTbm}}
%
\newcommand{\sbseries}{\fontseries{sb}\selectfont}
\newcommand{\ebseries}{\fontseries{eb}\selectfont}
\newcommand{\ubseries}{\fontseries{ub}\selectfont}
\setlength{\parindent}{0pt}
%
\begin{document}
%
\tableofcontents
%
\section{\FseriesName\ is `\Fseries' and so \WTbmName\ gives $\WTbm{\alpha>1}$, cf.\ $\alpha>1$}
%
\begin{tabbing}
\FseriesName\ is \hspace{0.2em} \= `\Fseries': \hspace{0.9em} \= The surrounding text is regular weight (medium).\hspace{0.5em} \= \WTbmName\ gives \hspace{0.5em} \= $\WTbm{\alpha>1}$.\\
%
{\sbseries\FseriesName\ is} \> {\sbseries `\Fseries':} \> {\sbseries The surrounding text is semi-bold.} \> {\sbseries \WTbmName\ gives} \> {\sbseries $\WTbm{\alpha>1}$.}\\
%
{\bfseries\FseriesName\ is} \> {\bfseries `\Fseries':} \> {\bfseries The surrounding text is bold.} \> {\bfseries \WTbmName\ gives} \> {\bfseries $\WTbm{\alpha>1}$.}\\
%
{\ebseries\FseriesName\ is} \> {\ebseries `\Fseries':} \> {\ebseries The surrounding text is extra bold.} \> {\ebseries \WTbmName\ gives} \> {\ebseries $\WTbm{\alpha>1}$.}\\
%
{\ubseries\FseriesName\ is} \> {\ubseries `\Fseries':} \> {\ubseries The surrounding text is black (ultra-bold).} \> {\ubseries \WTbmName\ gives} \> {\ubseries $\WTbm{\alpha>1}$.}
%
\end{tabbing}
%
\end{document}
输出如下:
答案3
去年,我为自己的一些产品解决了这个问题:
\DeclareDocumentCommand{\ForBf}{ mm }
{
\str_if_eq:eeTF
\f@series
\bfdefault
{#1}
{#2}
}
\bfdefault
这使用了 Expl3 语法。由于 的定义不一致,因此存在一些隐藏的挑战。在某些地方,它是使用 创建的(因此即使它没有参数,\newcommand
它也将被定义为宏),在其他地方,它是在没有 的情况下定义的(这发生在 fontspec 中的设置中)。² 使用 expl3 ³ 测试允许我们测试值而不必担心这些细节。否则,比较和 的唯一有效方法是执行以下操作:⁴\long
\long
\str_if_eq:eeTF
\bfdefault
\f@series
\edef\next{\itdefault}
\ifx\f@shape\next ...
我正在调整 LaTeX 徽标的外观以获得非 CM 字体以及粗体和斜体的正确间距。
从去年 3 月我在 LaTeX-3 项目邮件列表中提出这个问题开始,这种奇怪的差异就一直存在。
您可以放下电视或者F如果您只需要 if 的一个分支。不幸的是,stackexchange 上没有办法模拟 interface3 文档中使用的符号来指示这一点(在代码格式中为带下划线的斜体)。
这是 Frank Mittelbach 对这个问题的建议。显然,他自己也忘了
\str_if_eq:eeTF
。