重复字符 n 次

重复字符 n 次

我想创建一个新命令,它允许我执行repeat任何characters我想要的操作n times。经过一番搜索和尝试,我想到了这个:

\usepackage{multido}
\newcommand{\myrepeat}[2]{%
    \newcount\iterations%
    \iterations #1%
    \advance\iterations -1
    \multido{\iN=0+1}{\iterations}{#2\ }#2%
}

在生成的 PDF 中,命令后面有一些奇怪的间距,因此我添加了注释符号%,然后它就消失了。

我的问题是:有没有更好的方法可以做到这一点,它像这个一样容易理解,最好不要引入太多依赖关系?

multido如果不复杂,或者你能解释清楚,那么就不再复杂了,那么不用也行。我想用这个东西做这件事情是可以的,因为它的名字意味着多次执行某件事,但我不确定我是否multido采取了最简单、最干净的方式。

请注意,我的解决方案添加的空间比向 pdf 添加的项目少一个。减去一个的方法对我来说似乎过于冗长。

我现在有两个版本可以运行:

来自@egreg 修改的一个:

\makeatletter
\newcount\my@repeat@count% initialize a new counter for the loop
\newcommand{\myrepeat}[3]{% new command with 2 arguments
    \begingroup% ???
    \my@repeat@count=1% initialize at 1, so that there are argument - 1 iterations and the last iterations doesn't have a separator following it
    \@whilenum\my@repeat@count<#1\do{#2#3\advance\my@repeat@count1}#2% as long as the iteration count is smaller than the argument, advance, meaning that the counter will be increased by 1
    \endgroup% ???
}
\makeatother

\newcommand{\mediumgap}{%
    \myrepeat{5}{.....}{\ }
}

来自@christian 修改的内容:

\newcount\myloopcounter
\newcommand{\repeatit}[3][10]{%
    \myloopcounter1% initialize the loop counter
    \loop\ifnum\myloopcounter < #1
    #2#3%
    \advance\myloopcounter by 1%
    \repeat% start again
    #2%
}
\newcommand{\longgap}{%
    \repeatit[5]{.....}{\ }
}

我不知道这两种方法是否有优势。也许还有更好的方法可以删除最后一个空格或分隔符,而不是少做一次迭代,只写字符重复,而不使用分隔符。我引入了分隔符,因为我认为它可能很有用,而且它只是第三个参数。

答案1

没有包裹:

\documentclass{article}

\makeatletter
\newcount\my@repeat@count
\newcommand{\myrepeat}[2]{%
  \begingroup
  \my@repeat@count=\z@
  \@whilenum\my@repeat@count<#1\do{#2\advance\my@repeat@count\@ne}%
  \endgroup
}
\makeatother

\begin{document}

\myrepeat{4}{x}

\myrepeat{4}{\myrepeat{2}{x}}

\end{document}

为什么是组?因为它允许嵌套调用。

在此处输入图片描述

如果你只是想重复一个字符:

\documentclass{article}

\newcommand\myrepeat[2]{%
  \begingroup
  \lccode`m=`#2\relax
  \lowercase\expandafter{\romannumeral#1000}%
  \endgroup
}

\begin{document}

\myrepeat{4}{x}

\end{document}

正如 Ulrich Diez 正确评论的那样,此代码不允许计数器记录重复次数;为了支持这一点,稍微复杂一点的版本是

\newcommand\myrepeat[2]{%
  \begingroup
  \lccode`m=`#2\relax
  \lowercase\expandafter{\romannumeral\number\number#1 000}%
  \endgroup
}

\romannumeral触发第一个\number,从而扩展第二个;如果我们有,比如说,4,#1我们连续得到(其中表示一个空间标记

\romannumeral\number\number4•000
\romannumeral\number4000
\romannumeral4000
mmmm

相反,如果我们有\count27并且#1保存\count27值 4,我们得到

\romannumeral\number\number\count27•000
\romannumeral\number4000
\romannumeral4000
mmmm

如果我们有\foo(一个命名的计数器寄存器),再次保存值 4,我们有

\romannumeral\number\number\foo•000
\romannumeral\number4•000
\romannumeral4000
mmmm

所以的实例\number是必要的,以便涵盖第三种情况。这利用了空格结束对“明确”数字的搜索然后被忽略的事实(在第三种情况下,在第二个标记扩展后,空格标记不会被忽略\number)。

如果您还想在重复之间插入文本,第一种方法非常简单:只需从 1 开始循环。

\makeatletter
\newcount\my@repeat@count
\newcommand{\myrepeat}[3]{%
  % #1 = number of repetition
  % #2 = text to repeat
  % #3 = text in between
  \begingroup
  #2
  \my@repeat@count=\@ne
  \@whilenum\my@repeat@count<#1\do{#2#3\advance\my@repeat@count\@ne}%
  \endgroup
}
\makeatother

(不要用零重复来调用它)。

一种采用递归和旧思想的不同解决方案\romannumeral#1000会产生一长串 m,我们可以一次使用一个。

\documentclass{article}

\makeatletter
\newcommand\myrepeat[3]{%
  % #1 is the number of repetitions
  % #2 is the code to repeat
  % #3 is the code to put in the middle
  \expandafter\myrepeat@aux\expandafter{\romannumeral\number\number#1 000}{#2}{#3}%
}
\newcommand{\myrepeat@aux}[3]{\myrepeat@auxi{#2}{#3}#1;;}
\def\myrepeat@auxi#1#2#3#4{%
  \ifx#3;%
    \expandafter\@gobble % recursion has ended
  \else
    \expandafter\@firstofone % still one m to swallow
  \fi
  {\myrepeat@auxii{#1}{#2}{#4}}%
}
\def\myrepeat@auxii#1#2#3{%
  #1\ifx#3;\else#2\fi
  \myrepeat@auxi{#1}{#2}#3% restart the recursion
}
\makeatletter

\begin{document}

\myrepeat{4}{x}{-}

\myrepeat{1}{x}{-}

X\myrepeat{0}{x}{-}X

\end{document}

在此处输入图片描述

递归消耗每次处理一个 token,以区分是否只剩下一个步骤需要执行。递归重新启动时,第二个 token 会被放回。


不过,这只是为了学习。在实际应用中,我会这样做

\usepackage{xparse}

\ExplSyntaxOn
\NewExpandableDocumentCommand{\myrepeat}{O{}mm}
 {
  \int_compare:nT { #2 > 0 }
   {
    #3 \prg_replicate:nn { #2 - 1 } { #1#3 }
   }
 }
\ExplSyntaxOff

被称为像\myrepeat[-]{4}{x}得到

xxxxx

\myrepeat{3}{A}得到

AAA

答案2

这是没有任何包的版本,只使用普通的\loop\repeat

\documentclass{article}

\newcount\myloopcounter

\newcommand{\repeatit}[2][10]{%
  \myloopcounter0% initialize the loop counter
  \loop\ifnum\myloopcounter < #1 % Test if the loop counter is < #1
  #2%
  \advance\myloopcounter by 1 % 
  \repeat % start again
}

\begin{document}

\repeatit[5]{A}


\repeatit[20]{And now for something completely different\par}

\end{document}

在此处输入图片描述

答案3

值得一提的是,在 ConTeXt 中,您可以使用\dorecurse来重复某些操作。例如:

\dorecurse{10}{Hello world. }

将打印Hello world.10 次。当前迭代次数存储在宏中\recurselevel

答案4

在 OpTeX 中,您可以使用\fornum宏:

\def\myrepeat#1#2{\fornum 1..#1\do {#2}}

\myrepeat{4}{x}

\myrepeat{4}{\myrepeat{2}{x}}

\message{\myrepeat{4}{\myrepeat{2}{x}}} % prints xxxxxxxx on the terminal.

\bye

\fornum是完全可扩展的,您可以使用嵌套循环而无需打开或关闭组。

相关内容