我正在尝试创建一个可靠的命令,将其输入的第一个字符转换为大写。到目前为止,我还没有成功,特别是因为它需要在输入字符串包含命令本身时才能工作。最值得注意的是,当命令包含其自身时,我的尝试失败了。显然,以下方法不起作用:
\documentclass{scrartcl}
\usepackage{xstring}
\usepackage{etoolbox}
\begin{document}
\newcommand{\singleupper}[1]{\uppercase{\StrLeft{#1}{1}}\StrGobbleLeft{#1}{1}}
\newcommand{\optcap}[2]{\ifstrequal{cap}{#2}{\singleupper{#1}}{#1}}
\optcap{\optcap{asdf}{}}{cap}
\end{document}
导致:
! 未定义控制序列。\@xs@StrLeft@@ ...\@xs@arg@ii {#2}\edef \@xs@call {\noexpand \@testopt {\noe...
我怎样才能正确地做到这一点以及为什么我的尝试会失败?
编辑
我已经看到了一些不错的答案,它们在某种意义上都涉及到第二语言(latex3,lua......),在 latex2e 中没有完全可扩展的方法(可能使用包)?
答案1
你想要这样的东西吗?
\documentclass[border=10pt]{standalone}
\usepackage{xparse}
\begin{document}
\ExplSyntaxOn
\NewDocumentCommand \optcap { +m +m }
{
\tl_if_eq:nnTF { #2 } { cap }
{
\tl_mixed_case:n { #1 }
}{
#1
}
}
\ExplSyntaxOff
\optcap{asdf}{}
\optcap{\optcap{asdf}{}}{cap}
\end{document}
请注意,如果您输入 N/Y,则嵌套结果将意味着添加的字符是第一个,我认为这似乎不是您想要的。但我不确定我是否理解了,所以如果我应该删除它,请告诉我。
答案2
如果您愿意使用 LuaTeX(即使用lualatex
而不是进行编译pdflatex
),那么您可能可以省去一些宏扩展的麻烦。例如,您可以将以下内容放入 中foo.lua
:
-- The string s, with its first character converted to uppercase
function firstUpper(s)
first = unicode.utf8.upper(unicode.utf8.sub(s, 1, 1))
rest = unicode.utf8.sub(s, 2, -1)
return first .. rest
end
function optCap(s, opt)
if opt == 'cap' then
return firstUpper(s)
else
return s
end
end
您的.tex
文件可以是:
\documentclass{scrartcl}
\directlua{dofile('foo.lua')}
% \newcommand{\firstUpper}[1]{\directlua{tex.print(firstUpper('#1'))}}
\newcommand{\optcap}[2]{\directlua{tex.print(optCap('#1', '#2'))}}
\begin{document}
\optcap{asdf}{}
\optcap{asdf}{cap}
\optcap{\optcap{asdf}{}}{cap}
\end{document}
(如果您给它提供复杂的宏,这可能会失败,但我认为这是一个功能。)
至于为什么你最初的尝试失败了,这在第 3.2 节中有记录xstring 文档:
此包的宏不是纯粹可扩展的,即它们不能放在 的参数中
\edef
。嵌套宏也是不可能的。
要理解这里的“可扩展”是什么意思,你可以阅读这个网站上的答案,比如这,这,这和这。基本上,(等)的操作并非全部\StrLeft
发生在“嘴巴”(输入扩展处理器/语法例程)中;它会扩展为一些不可扩展的命令,需要在“胃”(执行处理器/语义例程)中处理。如果您真的想用宏来做,您可以使用来自的“可扩展”宏expl3
,如@cfr 的回答中所述。