
私は、 に対して任意の操作を実行できる新しいコマンドを作成したいと考えました。検索と試行錯誤の結果、次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 に項目を追加するよりも 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
\number
2番目を展開する最初のものをトリガーします。たとえば、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
したがって二\number
3 番目のケースをカバーするには、のインスタンスが必要です。これは、スペースによって「明示的な」数値の検索が終了し、無視されるという事実を利用しています (スペース トークンは、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
は完全に拡張可能で、グループを開いたり閉じたりせずにネストされたループを使用できます。