嵌套大写命令不起作用

嵌套大写命令不起作用

我正在尝试创建一个可靠的命令,将其输入的第一个字符转换为大写。到目前为止,我还没有成功,特别是因为它需要在输入字符串包含命令本身时才能工作。最值得注意的是,当命令包含其自身时,我的尝试失败了。显然,以下方法不起作用:

\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 的回答中所述。

相关内容