我正在尝试创建一种方法MakeCommands
,该方法将根据作为参数传递的基本名称生成几个命令。但是,我希望允许用户传递带空格的名称,因此必须从传递的参数中提取该名称以用作实际函数名称
我当前拥有的(为了简单起见,只创建一个命令)是:
\newcommand*{\MakeCommand}[1]
{
\expandafter\newcommand\csname the#1\endcsname{TEST}
}
这是可行的,因为诸如\MakeCommand{Bday}
创建命令的调用\theBday
会扩展为TEST
。但是,如果参数实际上是多个单词(\MakeCommand{Date of Birth}
),则必须使用 来调用创建的命令\csname theDate of Birth\endcsname
,这并不优雅。
因此我尝试了以下方法:
% \usepackage{xstring}
\newcommand*{\temp}{}
\newcommand*{\MakeCommand}[1]
{
\renewcommand*{\temp}{\StrSubstitute{#1}{ }{}}
\expandafter\newcommand\csname the\temp\endcsname{TEST}
}
基本上,使用xstring
的StrSubstitute
命令从传递的参数中提取空格并将其存储在 中\temp
。然后使用这个无空格版本的参数作为命令名称。
然而,这不起作用,我得到了多个错误。例如,对于以下 MWE:
\documentclass[a4paper,10pt]{article}
\usepackage{xstring}
\newcommand*{\temp}{}
\newcommand*{\MakeCommand}[1]
{
\renewcommand*{\temp}{\StrSubstitute{#1}{ }{}}
\expandafter\newcommand\csname the\temp \endcsname{TEST}
%\expandafter\newcommand\csname the#1\endcsname{TEST}
}
\MakeCommand{Date of Birth}
\begin{document}
\theDateofBirth
\end{document}
我收到以下错误:
Missing \endcsname inserted. \MakeCommand{Date of Birth}
Command \the already defined. \MakeCommand{Date of Birth}
Extra \endcsname. \MakeCommand{Date of Birth}
Missing \begin{document}. \MakeCommand{Date of Birth}
Undefined control sequence. ^^I\theDateofBirth
如果我注释掉该\expandafter...
行并\theDateofBirth
用 替换文档内容\temp
,则文件可以正常编译并输出“DateofBirth”,正如预期的那样。
我可以从其他读数中看出([A],[B],[C]) 这可能需要额外的\expandafter
s,但我无论如何也想不出把它们放在哪里以及为什么/如何。
这是一个将显示多个数据点的文件。MakeCommand
实际上应该创建三个相关命令。我打算做的是
\newcommand*{\temp}{}
\newcommand*{\MakeCommand}[1]
{
\renewcommand*{\temp}
{
% store spaceless version of parameter
\StrSubstitute{#1}{ }{}
}
\expandafter\newcommand\csname the\temp\endcsname{}% empty variable for use further ahead
\expandafter\newcommand\csname \temp\endcsname[1]
{
% store value of data point
\expandafter\renewcommand\csname the\temp \endcsname{#1}
}
\expandafter\newcommand\csname print\temp\endcsname
{
% print out formatted data point
\textbf{\temp:} \csname\the\temp\endcsname
}
}
因此,MakeCommands{Date of Birth}
将创建三个命令
\theDateofBirth
,最初是空的\DateofBirth
,用户稍后可以调用它来定义\theDateofBirth
\printDateofBirth
,打印出数据点
例如,\DateofBirth{August 31, 2016}
会导致\printDateofBirth
输出“出生日期:2016年8月31日”。
答案1
如果您想要删除的只是空格,那么核函数\zap@space
就是您所需要的:
\documentclass[a4paper,10pt]{article}
\makeatletter
\newcommand*{\MakeCommand}[1]{%
\expandafter\newcommand\csname the\zap@space #1 \@empty\endcsname
}
\makeatother
\MakeCommand{Date of Birth}{TEST}
\begin{document}
\theDateofBirth
\end{document}
我已经改变了语法以\MakeCommand
允许指定替换文本,否则它将毫无用处。
但是,这个the
前缀的选择确实不太好。
(较慢的) 实现如下\StrSubstitute
:
\documentclass[a4paper,10pt]{article}
\usepackage{xstring}
\newcommand*{\MakeCommand}[1]{%
\StrSubstitute{#1}{ }{}[\temp]%
\expandafter\newcommand\csname the\temp\endcsname
}
\MakeCommand{Date of Birth}{TEST}
\begin{document}
\theDateofBirth
\end{document}
答案2
这是一个利用可扩展替换的解决方案,与这个答案。这增加了一整套可扩展的替换系统,因此它不只是关于空格。一旦你这样做了
\setfreplace{removespaces}{ }{}
你可以说\freplace{removespaces}{Date of Birth}
,它会把每个空格替换为空(即删除空格)DateofBirth
可扩展。
尽管您可能不应该\the...
在名称中使用,因为该命名约定在 LaTeX 中用于其他事物。可能是\TheDateofBirth
,\showDateofBirth
或\printDateofBirth
。
这是一个 expl3 解决方案
\documentclass{scrartcl}
\usepackage{xparse,etoolbox}
\ExplSyntaxOn
\cs_generate_variant:Nn \cs_generate_variant:Nn { c }
\NewDocumentCommand \setfreplace { m +m +m }
{
\freplace_set:nnn { #1 } { #2 } { #3 }
}
\DeclareExpandableDocumentCommand \freplace { +m +m }
{
\freplace:nn { #1 } { #2 }
}
\quark_new:N \q_freplace
\cs_new:Npn \freplace:nn #1 #2
{
\exp_not:f { \use:c { freplace_#1:n } { #2 } }
}
\cs_new_protected:Npn \freplace_set:nnn #1 #2 #3
{
\cs_set:cpx { freplace_#1:n } ##1
{
\exp_not:c { freplace_#1_auxi:nw } { } ##1 { \exp_not:N \q_freplace }
}
\cs_set:cpx { freplace_#1_auxi:nw } ##1 ##2 ##
{
\exp_not:c { freplace_#1_nobraces:nfn }
{ ##1 } { \exp_not:c { freplace_#1_do:n } { ##2 } }
}
\cs_set:cpx { freplace_#1_nobraces:nnn } ##1 ##2
{
\exp_not:c { freplace_#1_auxii:nn } { ##1 ##2 }
}
\cs_generate_variant:cn { freplace_#1_nobraces:nnn } { nf }
\cs_set:cpx { freplace_#1_auxii:nn } ##1 ##2
{
\exp_not:N \str_if_eq:nnTF { \exp_not:N \q_freplace } { ##2 }
{ \exp_stop_f: ##1 }
{
\exp_not:c { freplace_#1_addbraces:nfw }
{ ##1 } { \exp_not:c { freplace_#1:n } { ##2 } }
}
}
\cs_set:cpx { freplace_#1_addbraces:nnw } ##1 ##2
{
\exp_not:c { freplace_#1_auxi:nw } { ##1 { ##2 } }
}
\cs_generate_variant:cn { freplace_#1_addbraces:nnw } { nf }
\cs_set:cpx { freplace_#1_do:n } ##1
{
\exp_not:N \tl_if_empty:nTF { ##1 }
{ \exp_stop_f: }
{
\exp_not:c { freplace_#1_auxiii:nww }
{ } ##1 \exp_not:n { #2 \q_freplace \q_stop }
}
}
\cs_set:cpx { freplace_#1_auxiii:nww } ##1 ##2 #2 ##3 \q_stop
{
\exp_not:N \str_if_eq:nnTF { \exp_not:N \q_freplace } { ##3 }
{ \exp_stop_f: ##1 ##2 }
{
\exp_not:c { freplace_#1_auxiii:nww }
{ ##1 ##2 \exp_not:n { #3 } } ##3 \exp_not:N \q_stop
}
}
}
\cs_generate_variant:Nn \freplace:nn { nV }
\cs_new_protected:Npn \tl_replace_nested:Nnn #1 #2 #3
{
\freplace_set:nnn { _tmp_ } { #2 } { #3 }
\tl_set:Nx #1 { \freplace:nV { _tmp_ } #1 }
}
\ExplSyntaxOff
\setfreplace{removespaces}{ }{}
\newcommand*{\MakeCommand}[1]
{\expandafter\newcommand\csname the\freplace{removespaces}{#1}\endcsname{TEST}}
\MakeCommand{Date of Birth}
\begin{document}
\theDateofBirth
\end{document}
更新后,这是完整的命令(我使用来自的命令etoolbox
来简化代码,该命令在帐户中有扩展)
\newcommand*\temp{}
\newcommand*\MakeCommand[1]
{\edef\temp{\freplace{removespaces}{#1}}%
\csdef{the\temp}{}%
\csedef{\temp}##1{\csdef{the\temp}{##1}}%
\csedef{print\temp}{\unexpanded{\textbf{#1:}} \noexpand\csuse{the\temp}}}
这里还有另一种解决方案,稍微不那么强大,没有 expl3(以防你害怕它并且因为某种原因不想使用它)
\documentclass{scrartcl}
\usepackage{etoolbox}
\long\def\usefirst#1#2{#1}
\long\def\usesecond#1#2{#2}
\def\strcmp#1#2{\ifnum\pdfstrcmp{\unexpanded{#1}}{\unexpanded{#2}}=0 \expandafter\usefirst\else\expandafter\usesecond\fi}
\def\strempty#1{\if\relax\detokenize{#1}\relax\expandafter\usefirst\else\expandafter\usesecond\fi}
\def\endreplace{\endreplace}
\def\nestedreplace#1{\csuse{nestedreplace:#1}}
\def\newnestedreplace#1#2#3{%
\csdef{nestedreplace:#1}##1{\csuse{nestedreplace:#1:A}##1{\endreplace}}%
\csdef{nestedreplace:#1:A}##1##{\csuse{doreplacement:#1}{##1}\csuse{nestedreplace:#1:B}}%
\csdef{nestedreplace:#1:B}##1{\strcmp{##1}{\endreplace}{}
{{\csuse{nestedreplace:#1}{##1}}\csuse{nestedreplace:#1:A}}}%
\csdef{doreplacement:#1}##1{\strempty{#1}{}{\csuse{doreplacement:#1:A}{}##1#2\endreplace\qend}}%
\csdef{doreplacement:#1:A}##1##2#2##3\qend{\strcmp{\endreplace}{##3}
{\unexpanded{##1##2}}{\csuse{doreplacement:#1:A}{##1##2#3}##3\qend}}%
}
\newnestedreplace{removespaces}{ }{}
\newcommand*{\MakeCommand}[1]
{\expandafter\newcommand\csname the\nestedreplace{removespaces}{#1}\endcsname{TEST}}
\MakeCommand{Date of Birth}
\begin{document}
\theDateofBirth
\end{document}