用于大写文本的 \ucshape 和 \textuc 命令(XeTeX、LuaTeX)

用于大写文本的 \ucshape 和 \textuc 命令(XeTeX、LuaTeX)

虽然我们有\textit\textsc\itshape\scshape等,但没有\textuc\ucshape来将其参数排版为大写。有\MakeUppercase,但是——因为大写不是字体样式——它不是字体选择命令,不能像字体选择命令那样使用。这就是为什么它在格式化标题等方面毫无用处。有西莫斯-埃格尔 解决方法,但这也有其局限性,例如当使用外来语言时:\section{daß}会产生»DAß«而不是»DASS«,等等。

\textuc传统上,获得正确/ 的唯一方法\ucshape似乎是通过创建虚拟字体,将所有小写字母替换为大写字母。虽然我看到一些人建议采用这种方法,但我认为没有人这样做过,可能是因为它既繁琐又不灵活,因为它总是与一种特定的字体绑定在一起。

我的问题是,既然我们有了 Xe 和 Lua,我们可以使用 OpenType 字体,并通过 fontspec 使用 OpenType 功能文件,那么重新考虑这个问题是否是个好主意。在这些功能文件中,我们可以定义可以打开和关闭的替换规则。在 OpenType 中,例如,f_i 连字符是通过这样的替换规则生成的,即“每当在代码中遇到f后跟 的时i,就用输出中的字形替换这两个”。暂时回答我自己的问题:是的,可能是。请考虑以下示例。[编辑:现在包括与来自barbara 包的命令f_i的比较\MakeTextUppercasetextcase提及。]

\documentclass{scrartcl}
\usepackage{fontspec,blindtext,microtype,filecontents,textcase}

\begin{filecontents*}{universalcaps.fea}
languagesystem DFLT dflt;
languagesystem latn dflt;

feature caps {

lookup ligatures {
  sub f_i by F I;
  sub f_l by F L;
  sub f_f_l by F F L;
  sub f_f_i by F F I;
  sub f_f by F F;
  sub f_j by F J;
  sub f_f_j by F F J;
  sub f_t by F T;
  sub f_f_t by F F T;
} ligatures;

lookup eszett {
  sub germandbls by S S;
} eszett;

lookup single {
  sub [a-z] by [A-Z];
  sub agrave by Agrave;
  sub aacute by Aacute;
  sub acircumflex by Acircumflex;
  sub atilde by Atilde;
  sub adieresis by Adieresis;
  sub aring by Aring;
  sub ccedilla by Ccedilla;
  sub egrave by Egrave;
  sub eacute by Eacute;
  sub ecircumflex by Ecircumflex;
  sub edieresis by Edieresis;
  sub igrave by Igrave;
  sub iacute by Iacute;
  sub icircumflex by Icircumflex;
  sub idieresis by Idieresis;
  sub eth by Eth;
  sub ntilde by Ntilde;
  sub ograve by Ograve;
  sub oacute by Oacute;
  sub ocircumflex by Ocircumflex;
  sub otilde by Otilde;
  sub odieresis by Odieresis;
  sub ugrave by Ugrave;
  sub uacute by Uacute;
  sub ucircumflex by Ucircumflex;
  sub udieresis by Udieresis;
  sub yacute by Yacute;
  sub thorn by Thorn;
  sub ydieresis by Ydieresis;
  sub oe by OE;
  sub ae by AE;
  sub scaron by Scaron;
  sub zcaron by Zcaron;
} single;

} caps;
\end{filecontents*}

\setmainfont[FeatureFile=universalcaps.fea]{TeX Gyre Termes}
\setsansfont[FeatureFile=universalcaps.fea]{TeX Gyre Heros}

\newcommand*{\ucshape}{\addfontfeature{RawFeature=+caps}}
\newcommand{\textuc}[1]{{\ucshape #1}}

\setkomafont{section}{\ucshape}

\begin{document}
\section{Lorem Ipsum}

\textuc{\blindtext
àéîàáâãäåæ çèéêëìíîï ðñòóôõö ùúûüýþÿœš
fi ff fl ffi ffl fj ffj}

\MakeTextUppercase{daß}
\textuc{daß}

\begin{titlepage}
\ucshape
\begin{center}
John Doe\par
{\huge Title}
\end{center}
\end{titlepage}

\end{document}

这将创建一个功能文件,为加载的任何字体添加一个名为的新功能,caps该功能可以像其他任何功能一样打开和关闭。请注意,这也适用于 TrueType 字体等{Georgia}fontspec似乎可以将 .fea 文件中的内容传输到非 OpenType 字体。

  • 是否存在我可能没有想到的潜在缺点?我仍然认为它似乎太简单了,难以置信。(虽然它可能很简单,但当然,在高级多语言字体中,可能仍然需要做大量工作才能完成所有小写字形)。

  • 有其他人做过或见过类似的事情吗?我很难相信我是第一个想到这个主意的人……

  • 如果到现在还没有人这样做,那么把它变成一个小包裹是不是一个好主意?

答案1

LuaTeX 中的完整实现:

\documentclass{article}
\usepackage{fontspec}
\usepackage{xcolor}
\usepackage{luacode}
\usepackage{luatexbase}
\usepackage{luatexbase-attr}

\newluatexattribute\uppercaseattr


\begin{luacode*}
  local ucattr = luatexbase.attributes.uppercaseattr
  local GLYPH = node.id("glyph")
  local function makeuppercase(head)
      local orighead = head
      local string = unicode.utf8
      while head do
          if head.id == GLYPH then
              local att = node.has_attribute(head,ucattr)
              if att then
                  if head.char == 223 then -- ß
                      -- insert two 'S' glyphs
                      head.char = 83
                      orighead = node.insert_before(orighead,head,node.copy(head))
                  elseif head.char == 64258 then -- fl
                      head.char = 70 -- F
                      orighead = node.insert_before(orighead,head,node.copy(head))
                      head.char = 76 -- L
                  elseif head.char == 64256 then -- ff
                      head.char = 70 -- F
                      orighead = node.insert_before(orighead,head,node.copy(head))
                      head.char = 70 -- F
                  elseif head.char == 64257 then -- fi
                      head.char = 70 -- F
                      orighead = node.insert_before(orighead,head,node.copy(head))
                      head.char = 73 -- I
                  elseif head.char == 64259 then -- ffi
                      head.char = 70 -- F
                      orighead = node.insert_before(orighead,head,node.copy(head))
                      head.char = 70 -- F
                      orighead = node.insert_before(orighead,head,node.copy(head))
                      head.char = 73 -- I
                  elseif head.char == 64260 then -- ffl
                      head.char = 70 -- F
                      orighead = node.insert_before(orighead,head,node.copy(head))
                      head.char = 70 -- F
                      orighead = node.insert_before(orighead,head,node.copy(head))
                      head.char = 76 -- L
                  else
                      head.char = string.byte(string.upper(string.char(head.char)))
                  end
              end
          end
          head = head.next
      end
      return orighead
  end

  function makeuppercase_hbox(head,groupcode)
      local orighead = head
      if groupcode == "adjusted_hbox" or groupcode == "hbox" then
           makeuppercase(head)
      end
      return orighead
  end

  luatexbase.add_to_callback("hpack_filter",makeuppercase_hbox,"makeuppercasehbox")
  luatexbase.add_to_callback("pre_linebreak_filter",makeuppercase,"makeuppercase")
\end{luacode*}

\newcommand*\ucshape{\uppercaseattr=1}
\DeclareTextFontCommand{\textuc}{\ucshape}

\begin{document}
\hsize 7.2cm
\newcommand\sample{Draußen \i \ij\ ffl fluffiest fish \textit{König} \textcolor{blue}{àéîàáâãäåæ} çèéêëìíîï  ff \hbox{ðñòóôõö} ùúûüýþÿœš}


Lowercase {\ucshape \sample} Lowercase

Lowercase \textuc{\sample} Lowercase

% textcolor doesn't work in LaTeX's \MakeUppercase
% Lowercase \MakeUppercase{\sample} Lowercase


\end{document}

得出

在此处输入图片描述

上述程序仅当给定属性被设置(为任意值)时才操作节点列表。属性被分组,就像任何 TeX 分配一样。

它比我想象的要复杂一些,因为我们需要\hbox{}分别处理 es。

答案2

虽然我不能提供基于宏的\ucshape,但我可以指出一种\textuc可以灵活应对重音的实现。

\documentclass{article}
\usepackage{fontspec}
\usepackage{microtype}
\usepackage{textcase}
\usepackage{xcolor}

\setmainfont{TeX Gyre Termes}
\setsansfont{TeX Gyre Heros}

\usepackage{xparse}
\ExplSyntaxOn
% Allow for likely changes to expl3
\cs_if_exist:NTF \text_uppercase:n
  { \tl_put_right:Nn \l_text_exclude_arg_tl { \textcolor } }
  {
    \cs_new_eq:NN \text_uppercase:n \tl_upper_case:n
    \tl_put_right:Nn \l_tl_change_case_exclude_tl { \textcolor } 
  }
\NewExpandableDocumentCommand \textuc { +m } { \text_uppercase:n {#1} }
\ExplSyntaxOff

\begin{document}
\section{Lorem Ipsum}

\textuc{Draußen \i \ij\ ffl fluffiest fish
  \textit{König} \textcolor{blue}{àéîàáâãäåæ} çèéêëìíîï  ff \hbox{ðñòóôõö} ùúûüýþÿœš}

\MakeTextUppercase{daß}
\textuc{daß}

\end{document}

这是可扩展的,可以复制一系列 LaTeX 输入,但目前存在一些极端情况:您需要一些可以生成“纯文本”的东西。正如在宏层中发生的那样,它可以与 XeTeX 以及 LuaTeX 一起使用。还有一个可以识别特定语言变化的版本(突厥语 i/无点 i、希腊语重音删除、立陶宛语重音“fun”、荷兰语 IJ 连字符)。

目前,中的实现expl3被称为,但在不久的将来\tl_upper_case:n它可能会被重新命名为(具有改进的功能):我的回答反映了这一点。\text_uppercase:n

相关内容