\def 中 \char 的扩展

\def 中 \char 的扩展

回答 另一个问题\def,我在尝试使用和的组合时遇到了一些问题\char。请考虑以下示例:

\documentclass{minimal}
\usepackage{etoolbox}
\usepackage{xstring}
\makeatletter
\def\title@A{a A}
\def\title@B{b B}

\def\gettitle#1{
  \IfInteger{#1}{%
    \def\@tmp{\char#1}%
    \ifcsundef{title@\@tmp}{\@tmp}{\csname title@\@tmp\endcsname}%
  }{%
    \ifcsundef{title@#1}{#1}{\csname title@#1\endcsname}%
  }
}
\begin{document}
\gettitle{65}  \gettitle{A}

\gettitle{66}  \gettitle{B}

\gettitle{67}  \gettitle{C}
\end{document}

输出:

啊啊啊

乙乙

抄送

似乎\@tmp不会扩展为单个字符,而是扩展为\char 65,这在中不起作用\csname ... \endcsname。我以为使用\edef\@tmp{\char#1}会起作用,但似乎\char是那些不会扩展的函数之一。

那么最后,是否有可能扩展\@tmpA不是 \char 65

答案1

这可以通过以下技巧来实现 \lowercase

\documentclass{minimal}
\usepackage{etoolbox}
\usepackage{xstring}
\makeatletter

\begingroup
  \catcode0=12 %
  \gdef\chrdef#1#2{%
    \begingroup
      \lccode0=\numexpr(#2)\relax
    \lowercase{\endgroup
      \def#1{^^@}%
    }%
  }%
\endgroup

\def\title@A{a A}
\def\title@B{b B}

\def\gettitle#1{
  \IfInteger{#1}{%
    \chrdef\@tmp{#1}%
    \ifcsundef{title@\@tmp}{\@tmp}{\csname title@\@tmp\endcsname}%
  }{%
    \ifcsundef{title@#1}{#1}{\csname title@#1\endcsname}%
  }
}
\begin{document}
\gettitle{65}  \gettitle{A}

\gettitle{66}  \gettitle{B}

\gettitle{67}  \gettitle{C}
\end{document}

结果

\lowercase(不可扩展命令)将参数字符标记转换为小写字符。这由 配置\lccode。唯一的例外是零。如果\lccode某个字符的 为零,则该字符保持不变。因此,示例使用代码为零的字符,可以用^^@TeX 符号表示为。但是,此字符通常具有无效的类别代码,因此在外部组中将其更改为 12(其他)。由于 的更改\lccode应在之后恢复,因此宏还使用一个组。

答案2

\char元不可扩展。在 XeTeX 和 LuaTeX 中,我们有\Uchar,即,因此可以生成任何字符。对于只有 256 种可能结果的 pdfTeX,我们可以设置一个查找表。例如

\catcode`\@=11 %
\ifdefined\Uchar
  \def\Xchar#1{%
    \detokenize\expandafter{\Uchar\numexpr #1\relax}%
  }
\else
  \catcode`\^^@=12 %
  \begingroup
    \gdef\Xchar#1{%
     \romannumeral-`\0\expandafter\Xchar@aux\expandafter{\numexpr #1\relax}%
    }
    \gdef\Xchar@aux#1{%
      \ifcsname Xchar@\romannumeral #1\endcsname
        \csname Xchar@\romannumeral #1\endcsname
      \else
        \errmessage{Character out of range}%
      \fi
    }
    \count@=-1 %
    \lccode`\X=`\X %
    \loop
      \advance\count@ by 1 %
      \ifnum\count@<256 %
      \lccode`\^^@ = \count@ %
      \lowercase{%
        \expandafter\gdef\csname Xchar@\romannumeral\count@\endcsname{^^@}%
      }
    \repeat
  \endgroup
\fi
\catcode`\@=12 %

提供\Xchar来完成这项工作。可以使用相同想法的更复杂版本来提供不同的类别代码字符,其实现方式如下\char_generate:nnexpl3(由于查找表是预先生成的,因此上述内容在使用时是可扩展的。)

相关内容