创建具有修改后的(大写)名称的宏

创建具有修改后的(大写)名称的宏

这是我正在尝试做的一个最简单的例子,其意图应该是显而易见的(参见评论)。

\documentclass{minimal}

\usepackage{xparse}

\NewDocumentCommand \sayhello { } {
    Hello
}

\ExplSyntaxOn
\NewDocumentCommand \foo { m } {
    \use:c {
        \MakeUppercase{\cs_to_str:N #1}
    }
    again
}
\ExplSyntaxOff

\foo{\sayhello} % Should construct \SAYHELLO macro.

\begin{document}

    \sayhello % Should output "Hello".

    \SAYHELLO % Should output "Hello again".

\end{document}

但是,我收到以下错误。

! Missing \endcsname inserted.
<to be read again> 
                   \protect 
l.18 \foo{\sayhello}

我想我在上面的代码中缺少一些适当的扩展,但我不确定如何去做。

答案1

您必须实际定义大写变体。当前代码的工作方式是,每当您使用\foo尚未定义的大写命名变体时,直接尝试调用它。

另外,您不能使用\MakeUppercaseinside of \use:c(或\csname ...\endcsname),因为它不可扩展。相反,您可以使用\str_uppercase:nprovided by expl3。下面使用f它的 -variant\cs_to_str:N在发生大写之前先进行扩展。

请注意,这\foo仅适用于无参数宏。

\documentclass[]{article}

\ExplSyntaxOn
\NewDocumentCommand \foo { m }
  {
    \exp_args:Nc \NewDocumentCommand { \str_uppercase:f { \cs_to_str:N #1 } } {}
      { #1~ again }
  }
\ExplSyntaxOff

\NewDocumentCommand \sayhello {} {Hello}
\foo\sayhello

\begin{document}
\sayhello

\SAYHELLO
\end{document}

在此处输入图片描述

答案2

主要问题\MakeUppercase

  • 触发处理级联,还会产生不可扩展的标记,这些标记不适合作为控制序列标记名称的组成部分。
  • 结果以嵌套在花括号组中的形式传递。

\MakeUppercase定义如下:

\DeclareRobustCommand\MakeUppercase[1]{%
  {% -- opening brace of brace-group
    \def\i{I}%
    \def\j{J}%
    \def\reserved@a##1##2{\let##1##2\reserved@a}%
    \expandafter\reserved@a\@uclclist\reserved@b{\reserved@b\@gobble}%
    \let\UTF@two@octets@noexpand\@empty
    \let\UTF@three@octets@noexpand\@empty
    \let\UTF@four@octets@noexpand\@empty
    \protected@edef\reserved@a{\uppercase{#1}}%
    \reserved@a % -- this holds the text wrapped in \uppercase, some symbol-delivering control-sequences replaced by control-sequences that yield the uppercase variant
  }% -- closing brace of brace-group
}%

\MakeUppercase旨在用于排版目的,而不是用于提供/修改控制序列标记的名称。

为了编程目的/为了提供/修改控制序列标记的名称,expl3 带来了\str_uppercase:n/ \str_uppercase:f

不用于日常使用,只是为了展示问题下面的代码提供了\MakeUppercase不将内容放入花括号组的变体。

在任何情况下,在控制序列名称的上下文中, \str_uppercase:n/\str_uppercase:f都是首选:
\MakeUppercase的大写例程取决于字体编码,并且可能会提供标记,这些标记在排版时会产生所讨论符号的大写变体,但不能用作宏名称的组成部分。

\documentclass{minimal}
\usepackage[T1]{fontenc}

\makeatletter
\DeclareRobustCommand\MyMakeUppercase[1]{%
  {%
    \def\i{I}%
    \def\j{J}%
    \def\reserved@a##1##2{\let##1##2\reserved@a}%
    \expandafter\reserved@a \@uclclist\reserved@b{\reserved@b\@gobble}%
    \let\UTF@two@octets@noexpand\@empty
    \let\UTF@three@octets@noexpand\@empty
    \let\UTF@four@octets@noexpand\@empty
    \protected@edef\reserved@a{\uppercase{#1}}%
    % \show\reserved@a
  \expandafter}\reserved@a
}%
\makeatother


\usepackage{xparse}

\NewDocumentCommand\sayhello{}{Hello}

\ExplSyntaxOn
\NewDocumentCommand \foo { m } {
    \MyMakeUppercase{\exp_not:n{\exp_args:Nc\NewDocumentCommand}{\cs_to_str:N #1}}{}
    {#1~again}
}
\ExplSyntaxOff

\foo{\sayhello} % Should construct \SAYHELLO macro.

\begin{document}

    \sayhello % Should output "Hello".

    \SAYHELLO % Should output "Hello again".

\end{document}

在此处输入图片描述

相关内容