如何定义一个宏来保存 \f@series 假定的粗体值?

如何定义一个宏来保存 \f@series 假定的粗体值?

首先,我只对适用于 的解决方案感兴趣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为粗体文本的值。

概括

  1. 有没有办法解决我的“狭义问题”?它能在我的 MWE 背景下发挥作用吗?
  2. 如果我的狭隘问题没有解决方案,使得它仍然在我的 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最终会被设置为错误值。更详细地说:首先请注意,如果我们不加载任何包,bxLaTeX 将把 和 设置为选定的权重\bfseries。1另一方面\textbf,包和包都将和设置为选定的权重。现在,如果将上述代码放在序言中,那么对于包,最终会被错误地设置为。即使当我们使用该包时,无论上述代码是放在序言中还是文档正文中,最终都会正确设置为。newtxtextNotob\bfseries\textbfnewtxtext\DefaultBoldWeightbxNoto\DefaultBoldWeightb

1中还存储了值\bfdefault。令人惊讶的是,如果我们不加载任何包,则为\bfdefaultb\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”命令。

与前一个“狭义问题”的关系(以及缺乏关系)

我原本以为这个问题的答案会用到上面狭义问题的答案。然而,我不再这么认为了,因为我有时间思考约瑟夫·赖特的回答以及对该答案的评论中的讨论。

我的主要认识是这样的:完全主流有一个包

  1. 定义了几种字体粗细,可以说,为了达到“weight-transparent”命令的目的,这些字体都应该算作“粗体” \bm,并且
  2. 并非所有这些粗细都具有以 开头的字体系列值/描述符2b

2对于给定的字体粗细,其字体系列值(或者描述符\fontseries) 是我们应该作为选择该字体粗细的参数的东西。

就上述第 2 点而言,请注意标准描述符集(至少根据LaTeX 2ε 字体选择自 2021 年 3 月起,第 5 页)包括sb(半粗体)、eb(特粗体)和ub(极粗体),以及bx(粗体扩展)和sbx(半粗体扩展)。事实上,请注意

(一)NotoSans 字体有以下几种粗体:bsbebub
(ii) 默认 LaTeX 字体支持的粗体之一是bx;以及
(iii) 支持的粗体之一是kpfontssbx

所以我们甚至不能假设描述符不超过两个字母组成。

因此,在没有关于将使用哪种字体的更多具体信息的情况下,“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 ...

  1. 我正在调整 LaTeX 徽标的外观以获得非 CM 字体以及粗体和斜体的正确间距。

  2. 从去年 3 月我在 LaTeX-3 项目邮件列表中提出这个问题开始,这种奇怪的差异就一直存在。

  3. 您可以放下电视或者F如果您只需要 if 的一个分支。不幸的是,stackexchange 上没有办法模拟 interface3 文档中使用的符号来指示这一点(在代码格式中为带下划线的斜体)。

  4. 这是 Frank Mittelbach 对这个问题的建议。显然,他自己也忘了\str_if_eq:eeTF

相关内容