文字をn回繰り返す

文字をn回繰り返す

私は、 に対して任意の操作を実行できる新しいコマンドを作成したいと考えました。検索と試行錯誤の結果、次repeatのようなコマンドが思いつきました。charactersn times

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

結果の PDF ではコマンドの後に奇妙なスペースがあったので、コメント記号を追加し%たら消えました。

私の質問は、これと同じくらい理解しやすく、できれば多くの依存関係を導入しない、より良い方法はあるでしょうか?

あまりmultido複雑でない場合、または説明できれば複雑ではなくなる場合は、使用しない方法も問題ありません。multidoその名前は何かを複数回実行することを意味するので、このような場合に使用しても問題ないと思いますが、最も簡単でクリーンな方法をとったかどうかはわかりません。

私の解決策では、PDF に項目を追加するよりも 1 つ少ないスペースが追加されることに注意してください。1 つ減算する方法は、疑わしいほど冗長に思えます。

現在、2 つのバージョンが動作しています:

@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 回減らして、セパレーターなしで繰り返す文字だけを書き込むのではなく、最後の空白または区切り文字を削除する方がよい方法もあるかもしれません。セパレーターを導入したのは、便利だと思ったからです。これは 3 番目のパラメーターにすぎません。

答え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\number2番目を展開する最初のものをトリガーします。たとえば、4つあるとすると#1、(スペーストークンを表します)

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

代わりに、\count27として、値4を保持すると、次のようになります#1\count27

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

\foo(名前付きカウンタレジスタ)が値4を保持している場合、

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

したがって\number3 番目のケースをカバーするには、のインスタンスが必要です。これは、スペースによって「明示的な」数値の検索が終了し、無視されるという事実を利用しています (スペース トークンは、2 番目の\numberトークンの展開後の 3 番目のケースでは無視されません)。

繰り返しの間にテキストも入れたい場合は、最初の方法は非常に簡単です。ループを 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一度に 1 つずつ使用できる 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}

ここに画像の説明を入力してください

再帰は消費する一度に 2 つのトークンを出力して、あと 1 つのステップだけ実行する必要があるかどうかを区別します。再帰が再開されると、2 番目のトークンが戻されます。


しかし、これはあくまでも研究のためのものです。実際の応用では、

\usepackage{xparse}

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

\myrepeat[-]{4}{x}呼ばれるのと同じように

xxxx さん

そして\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. }

10 回印刷されますHello world.。現在の反復回数はマクロに保存されます\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は完全に拡張可能で、グループを開いたり閉じたりせずにネストされたループを使用できます。

関連情報