如何识别新数学字体的编码和系列?

如何识别新数学字体的编码和系列?

这个问题,sfranky 要求在 上添加\bm{\phi}由 包生成的双重重音符号。和包bm中都实现了双重重音符号,但这些包与 配合得不好。 我自己发现:可以使用 来使其工作。amsmathaccentsbm\use@mathgroup

现在,在回答 sfranky 的问题时,我建议使用

\use@mathgroup{\M@OMS}{5}{\bm{\phi}}

\phi得到包可以处理的粗体accents。但是,其中一半只是有根据的猜测。OMS我认为是编码(在本例中可能应该是OML),5是的字体系列\bm{phi}。虽然它似乎有效,但这肯定不是正确的做法。

因此我的问题是:有没有办法自动识别我要使用的符号的编码和系列?

答案1

可以通过查看符号的系列\mathcode(这适用于明确的字符,如1a等;例如,\the\mathcode`1给出十六28721进制的符号"7031)或查看\meaning以 开头的符号\mathchar(例如\meaning\phi给出\mathchar"11E)来提取符号的系列。四个十六进制数字中的第二个是数学系列(如果少于这个数字,则前导数字为零)。例如,1具有数学代码"7031,因此它来自系列0(运算符),并且\phi具有数学代码"011E,因此它来自系列1(字母)。

要从符号中获取家族,您可以按照以下方式进行:查看\meaning符号的。通常带有重音符号(1\phi等)的符号通常具有 ,\meaning其为\mathchar"....the character 1或。对于第一种类型,您必须从 中the letter a删除并仅保留数字。对于第二种类型,您必须检查 是否以 开头,查看,然后将其转换为十六进制(例如,通过使用\mathchar\meaning\meaningthe\mathcodebinhex.tex)。在每种情况下,您可能需要用前导零填充数字以可靠地提取第二位数字。

要说出字符的含义是以\mathchar还是以开头the,有多种方法。在这里,我使用了与 相同的方法,amsmath.sty以便自动\dots。由于\meaning生成 catcode 12 个字符,因此必须生成一个\、一个m、一个t等 catcode 为 12 的字符来进行测试。这样做的一种方法是使用大写/小写技巧(原理与我对问题的回答相同如何制作真正的反斜杠(转义)字符?):取 12 个字符的 catcode(例如!?等),并将其大写版本设为\m等,然后将整个定义大写。

以下代码展示了如何实现这一切。我已经对其进行了注释,希望您能看懂。

\documentclass{article}

% the code works with all font packages
%\usepackage{lmodern}
%\usepackage{fourier}
%\usepackage[utopia]{mathdesign}
%\usepackage[charter]{mathdesign}
%\usepackage[garamond]{mathdesign}
%\usepackage{txfonts}
%\usepackage{pxfonts}
%\usepackage{mathpazo}

\usepackage{amsmath}
\usepackage{bm,accents}
\input{binhex}% for hex conversion

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%% CODE TO DETECT MATH FAMILY %%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
\makeatletter
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Utility macros to pad zeros (e.g. transform 34 into 0034)
% The delimiter is \empty so that if it is expanded, it does nothing
\def\@pad@four@zeros#1{\@pad@four@zeros@aux#1\empty\empty\empty\empty}%
\def\@pad@four@zeros@aux#1#2#3#4\empty{%
  \ifx#1\empty 0\fi\ifx#2\empty 0\fi\ifx#3\empty 0\fi\ifx\\#4\\0\fi#1#2#3#4%
}
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Macro extracting the second digit (e.g. 7163 -> 1)
\def\@extract@second@of@four#1#2#3#4\@nil{#2}%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% new boolean which will be used to test if a \meaning begins with \mathcha (e.g. \mahchar"11E)
\newif\if@begins@by@mathchar@
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% uppercase trick to obtain characters with catcode 12
\begingroup
\uccode`!=`\\ % ! is \ with catcode 12
\uccode`?=`m  % ? is m with catcode 12
\uccode`,=`a  % , is a with catcode 12
\uccode`.=`t  % . is t with catcode 12
\uccode`;=`h  % ; is h with catcode 12
\uccode`/=`c  % / is c with catcode 12
\uccode`|=`r  % | is r with catcode 12
\uppercase{\endgroup
\def\@if@begins@by@mathchar@#1#2#3#4#5#6#7#8#9\@nil{%
  \@begins@by@mathchar@false % initiate boolean to false
  % test if #1#2#3#4#5#6#7#8 is !?,.;/;, i.e. \mathcha
  \ifx !#1\ifx ?#2\ifx ,#3\ifx .#4\ifx ;#5\ifx /#6\ifx ;#7\ifx ,#8%
    \@begins@by@mathchar@true % switch boolean to true
  \fi\fi\fi\fi\fi\fi\fi\fi
  \if@begins@by@mathchar@ % if boolean true
    \expandafter\@firstoftwo
  \else % if boolean false
    \expandafter\@secondoftwo
  \fi
}
% macro which strips prefix \mathchar
\gdef\@strip@mathchar@prefix!?,.;/;,|#1\@nil{#1}%
% end of uppercase trick
}
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% new boolean which will be used to test if a \meaning begins with the (e.g. the character 1)
\newif\if@begins@by@the@
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% uppercase trick to obtain characters with catcode 12
\begingroup
\uccode`!=`t % ! is t with catcode 12
\uccode`?=`h % ? is h with catcode 12
\uccode`,=`e % , is e with catcode 12
\uppercase{\endgroup
\def\@if@begins@by@the@#1#2#3#4\@nil{%
  \@begins@by@the@false % initiate boolean to false
  % test if #1#2#3 is !?, i.e. the
  \ifx !#1\ifx ?#2\ifx ,#3%
    \@begins@by@the@true % switch boolean to true
  \fi\fi\fi
  \if@begins@by@the@ % if boolean true
    \expandafter\@firstoftwo
  \else % if boolean false
    \expandafter\@secondoftwo
  \fi
}
}
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% macro which finds the font family of a math glyph
% does not work for characters modified by amsmath (because of the 
% \DOTSB before them) but as they are not normally accented, it 
% shouldn't be a problem
\def\find@font@family#1{%
% #1 = glyph from which to extract font family
  \edef\@the@mathcode@{-1}% dummy definition (-1 will give a 0 family)
% test if #1 begins with \mathchar
  \expandafter\@if@begins@by@mathchar@\meaning#1\@nil
%   if so, store the value of \mathchar inside \@the@mathcode@
    {\edef\@the@mathcode@{%
         \number\expandafter\@strip@mathchar@prefix\meaning#1\@nil}}%
%   otherwise, do nothing
    {}%
% test if #1 begins with the
  \expandafter\@if@begins@by@the@\meaning#1\@nil
%   if so, store the mathcode inside \@the@mathcode@
    {\edef\@the@mathcode@{\the\mathcode`#1}}%
%   otherwise, do nothing
    {}%
% convert the mathcode into hex with package binhex.tex
  \edef\@the@mathcode@hex{\hex{\@the@mathcode@}}%
% convert the hex number to a 4-digit one
  \edef\@the@mathcode@hex{\expandafter\@pad@four@zeros
                          \expandafter{\@the@mathcode@hex}}%
% store the second digit (which is the math family) in \@the@math@family
  \edef\@the@math@family{%
     \expandafter\@extract@second@of@four\@the@mathcode@hex\@nil}%
}
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%% NEW \accbm MACRO %%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
\newcommand{\accbm}[1]{%
% store the font family inside \@the@math@family
  \find@font@family{#1}%
% assign counter \@tempcnta to \@the@math@family so that \bm@boldtable
% gives the right corresponding bold family offset
  \@tempcnta=\@the@math@family
% select the right \fam and apply it to \bm
% \@the@math@family+\bm@boldtable is the number of the bold family
  \use@mathgroup{}% not currently used by LaTeX so can be empty
                {\number\numexpr\@the@math@family+\bm@boldtable}%
                {\bm{#1}}%
}
%
\makeatother
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%% END OF CODE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}

\newcommand{\test}[1]{$\hat{\dot{\bm{#1}}} \hat{\dot{\accbm{#1}}} \bm{{\hat{\dot{#1}}}}$\par}

\test{\phi}
\test{A}
\test{1}
\test{\Gamma}
\test{+}

% should give 3 but gives 0 if amsmath is loaded
\makeatletter$\find@font@family{\sum}\@the@math@family$\makeatother

\end{document}

在测试中,我比较了\hat{\dot{\bm{...}}}\hat{\dot{\accbm{...}}}\bm{{\hat{\dot{...}}}}(最后一个将重音符号加粗,但可以立即使用)。以下是使用 mathdesign/utopia 字体时的结果(从左到右):

使用 phi 和 A 测试重音命令


对代码的一些解释。

1.关于编码。编码信息(例如\M@OMS\M@OML等)实际上并非由 LaTeX 使用。\meaning这些宏的 通常是\default@M .\default@M \noaccents@ .其中\default@M为空,并由\noaccents@amsmath 的数学重音机制用于在系列之间切换0,并7避免在数学字母表内部使用重音时出现奇怪的结果(尝试$\mathcal{\hat{A}}$使用和不使用 amsmath 来查看效果)。

一旦获得了数字,就可以通过查看 \the\textfont2 (通常为 \OMS/cmsy/m/n/10)并提取和 第一个\fam之间的标记来提取编码,这可以通过分隔宏来完成:\/

\makeatletter
\def\@extract@encoding@aux#1#2/#3\@nil{#2}
\newcommand{\extractencoding}[1]{%
  \expandafter\@extract@encoding@aux\detokenize\expandafter{\the\textfont#1}/\@nil
}
\makeatother
\extractencoding{0} \extractencoding{1} \extractencoding{2} \extractencoding{3} \extractencoding{4}

如果当前未使用该字体系列,则通过这种方式提取的编码将为“nullfont”。

2.关于boldtable宏。\bm@boldtable宏保存了系列和它们的粗体版本之间的偏移量,并\ifcase以以下方式存储在结构中:

\ifcase \@tempcnta 9\relax \or 9\relax \or 9\relax \or 9\relax \or \z@ \or \z@ \or \z@ \or \z@ \or \z@ \else \z@ \fi .

这意味着偏移量9对于\fam0到 是\fam3,对于所有其他的偏移量为零。要访问这些数字,必须将当前\fam数字存储在计数寄存器中\@tempcnta,您可以使用

\@tempcnta=\@the@math@family

然后你得到相应的粗体\fam数字

\number\numexpr\@the@math@family+\bm@boldtable

答案2

我不知道有任何预先存在的机制可以识别符号的编码和系列。

encguide 包可能会提供一些启发。它使用如下命令来打印每个系列中的编码集:

\ftable{cmr10}{OT1}

具体来说,它会打印属于某个家族和编码的每个字符,如下所示:

\font\X=cmr10
\X{\char86} % "V"

系列和编码列表位于指南导览(从第 1298 行开始)。

话虽如此,我不确定您是否可以从给定的符号名称或字符中提取家族和编码。我尝试使用该ifthen包进行比较(即\X\ifthenelse{\equal{V}{\char86}}{Same}{Different}),但比较没有按预期进行。如果可以进行比较,则可以将符号与每个家族的每个字符进行比较。

与构建这个反向映射相比,对于 sfranky(以及有类似问题的其他用户)来说,通过 X Ǝ T E X 或 LuaTeX使用 unicode 可能是一个明智的选择。

虽然这不是一个解决方案,但我希望这能提供一些有用的思考。

答案3

这实际上不是对我问题的回答,而是解释了为什么包bm无法识别编码和系列是错误的原因。举个例子,在via\mathcal中定义fontmath.ltx

\DeclareSymbolFontAlphabet{\mathcal}{symbols}

实际上,这使得\mathcal扩展为

\use@mathgroup\M@OMS\symsymbols

在数学模式下使用时,即同时提供编码( \M@OMS)和系列( )。这使和包能够正确放置多个重音。因此,对所讨论问题的正确修复应该是最终扩展到正确的。\symsymbolsamsmathaccents\bm\use@mathgroup<encoding><family>

相关内容