有没有一种简单的方法来定义一个命令,该命令接受一个单词(首字母缩写)并在每个字符后插入一个句点?也就是说,我想定义一个\init{abc}
输出“ABC”的命令(不假设输入参数中的字符数)。
预期用途是能够根据所需样式将 的输出切换\init{#1}
为\uppercase{#1}
或\textsc{#1}
,或像《纽约客》那样区分首字母缩略词,如 CPU(每个字母单独发音)和 NASA(发音为一个单词)。
答案1
您可以在每个标记处拆分输入,然后用句点分隔它们;\initformat
您可以选择格式,参数应该是一个参数宏,例如\MakeUppercase
或\textsc
。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\init}{m}
{
\tanh_init:n { #1 }
}
\NewDocumentCommand{\initformat}{m}
{
\cs_set_eq:NN \tanh_init_format:n #1
}
\seq_new:N \l_tanh_init_seq
\cs_new_protected:Nn \tanh_init:n
{
\seq_set_split:Nnn \l_tanh_init_seq { } { #1 }
\tanh_init_format:n { \seq_use:Nn \l_tanh_init_seq { . } .\@ }
}
\ExplSyntaxOff
\initformat{\MakeUppercase} % initialize
\begin{document}
\init{abc}
\initformat{\textsc}
\init{abc}
\end{document}
如果首字母缩写后面跟着句点,而您想删除后面的句点,您可以检查它并做出决定。在我使用的示例中,\xspaceskip
效果更加明显。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\init}{m}
{
\tanh_init:n { #1 }
}
\NewDocumentCommand{\initformat}{m}
{
\cs_set_eq:NN \tanh_init_format:n #1
}
\seq_new:N \l_tanh_init_seq
\cs_new_protected:Nn \tanh_init:n
{
\seq_set_split:Nnn \l_tanh_init_seq { } { #1 }
\tanh_init_format:n { \seq_use:Nn \l_tanh_init_seq { . } }
\tanh_init_period:
}
\cs_new_protected:Nn \tanh_init_period:
{
\peek_charcode:NTF . { \@ } { \tanh_init_format:n { . } \@ }
}
\ExplSyntaxOff
\xspaceskip=20pt
\initformat{\MakeUppercase} % initialize
\begin{document}
\init{abc} whatever
\init{abc}. A period!
\initformat{\textsc}
\init{abc} whatever
\init{abc}. A period!
\end{document}
如果要保留字距调整,需要事先进行测试.
:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\init}{m}
{
\tanh_init:n { #1 }
}
\NewDocumentCommand{\initformat}{m}
{
\cs_set_eq:NN \tanh_init_format:n #1
}
\seq_new:N \l_tanh_init_seq
\cs_new_protected:Nn \tanh_init:n
{
\seq_set_split:Nnn \l_tanh_init_seq { } { #1 }
\tanh_init_period:
}
\cs_new_protected:Nn \tanh_init_period:
{
\peek_charcode_remove:NTF .
{
\tanh_init_format:n { \seq_use:Nn \l_tanh_init_seq { . } . } \spacefactor\sfcode`.~
}
{
\tanh_init_format:n { \seq_use:Nn \l_tanh_init_seq { . } . } \@
}
}
\ExplSyntaxOff
\xspaceskip=20pt
\initformat{\MakeUppercase} % initialize
\begin{document}
\init{abp} whatever
\init{abp}. A period!
\initformat{\textsc}
\init{abp} whatever
\init{abp}. A period!
\textsc{a.b.p.} A period!
\end{document}
答案2
一种方法是:
\documentclass{article}
\begin{document}
\newcommand{\init}[1]{%
\let\nextinit=\relax
\if\relax\noexpand#1\relax\else#1.\let\nextinit=\init\fi\nextinit}
\init IBM\relax{} is an abbreviation, as is
\init GNU\relax. What is \init SPECTRE{}?
\end{document}
\init
现在被定义为一个接受单个参数的函数。因此,在 中\init IBM
,首先,只有 才是I
的参数\init
。这个想法是\init
检查其参数是否等于\relax
。如果是,它什么也不做并停止。如果不是,那么它会打印参数加上 .,然后复制自身。因此它会继续,直到遇到\relax
。它也会停止在{}
(即使严格来说,这并不是\relax
,但很好)。
您还可以尝试使用其他停止标准,例如特殊字符\@ifnextchar
请参阅理解 \@ifnextchar。