虽然我们有\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
的比较\MakeTextUppercase
textcase
提及。]
\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