
Eu queria criar um novo comando, que me permitisse fazer repeat
qualquer coisa characters
que eu quisesse n times
. Depois de algumas pesquisas e tentativas, cheguei a isto:
\usepackage{multido}
\newcommand{\myrepeat}[2]{%
\newcount\iterations%
\iterations #1%
\advance\iterations -1
\multido{\iN=0+1}{\iterations}{#2\ }#2%
}
Havia um espaçamento estranho após o comando no PDF resultante, então adicionei os símbolos de comentário %
e ele desapareceu.
Minha pergunta é: existe uma maneira melhor de fazer isso, que seja tão fácil de entender quanto esta, de preferência sem introduzir muitas dependências?
Um sem multido
também está bom, se não for muito complicado, ou se você puder explicar, para que não seja mais complicado. Acho que usar multido
para tal coisa é aceitável, já que seu nome significa fazer algo várias vezes, mas não tenho certeza se escolhi a maneira mais fácil e limpa de fazer isso.
Observe que minhas soluções adicionam um espaço a menos do que adicionam itens ao pdf. A maneira de subtrair um parece-me suspeitamente prolixa.
Eu tenho duas versões funcionando agora:
O de @egreg modificado:
\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}{.....}{\ }
}
O de @christian modificado:
\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]{.....}{\ }
}
Não sei se um tem alguma vantagem sobre o outro. Talvez haja também uma maneira melhor de remover o último espaço em branco ou caractere de separação, em vez de fazer uma iteração a menos e escrever apenas os caracteres para repetir novamente sem o separador. Introduzi o separador porque achei que poderia ser útil e é apenas um terceiro parâmetro.
Responder1
Sem pacotes:
\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}
Por que o grupo? Ele permite chamadas aninhadas.
Se você quiser apenas repetir um caractere:
\documentclass{article}
\newcommand\myrepeat[2]{%
\begingroup
\lccode`m=`#2\relax
\lowercase\expandafter{\romannumeral#1000}%
\endgroup
}
\begin{document}
\myrepeat{4}{x}
\end{document}
Como comenta Ulrich Diez, com razão, este código não permitiria um registro contador como número de repetições; para apoiar isso, uma versão um pouco mais complicada é
\newcommand\myrepeat[2]{%
\begingroup
\lccode`m=`#2\relax
\lowercase\expandafter{\romannumeral\number\number#1 000}%
\endgroup
}
\romannumeral
aciona o primeiro \number
que expande o segundo; se tivermos, digamos, 4 à medida que #1
obtemos sucessivamente (onde •
denota um token de espaço
\romannumeral\number\number4•000
\romannumeral\number4000
\romannumeral4000
mmmm
Se, em vez disso, tivermos \count27
as #1
e \count27
mantiver o valor 4, obteremos
\romannumeral\number\number\count27•000
\romannumeral\number4000
\romannumeral4000
mmmm
Se tivermos \foo
(um registrador contador nomeado), novamente mantendo o valor 4, temos
\romannumeral\number\number\foo•000
\romannumeral\number4•000
\romannumeral4000
mmmm
Portantodoisinstâncias de \number
são necessárias, a fim de cobrir o terceiro caso. Isto explora o fato de que um espaço encerra a busca por um número “explícito” e é então ignorado (o token de espaço não é ignorado no terceiro caso, após a expansão do segundo \number
token).
Se você também quiser colocar um texto entre as repetições, a primeira abordagem é muito simples: basta iniciar o loop em 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
(não chame isso com zero repetições).
Uma solução diferente com recursão e a ideia antiga de \romannumeral#1000
que produz uma longa sequência de m's que podemos consumir um de cada vez.
\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}
A recursão consomedoistokens por vez, a fim de distinguir se há apenas mais uma etapa a ser executada. O segundo token é devolvido quando a recursão é reiniciada.
No entanto, isso é apenas para estudo. Em uma aplicação do mundo real eu faria
\usepackage{xparse}
\ExplSyntaxOn
\NewExpandableDocumentCommand{\myrepeat}{O{}mm}
{
\int_compare:nT { #2 > 0 }
{
#3 \prg_replicate:nn { #2 - 1 } { #1#3 }
}
}
\ExplSyntaxOff
ser chamado gostaria \myrepeat[-]{4}{x}
de receber
xxxx
e \myrepeat{3}{A}
para conseguir
AAA
Responder2
Aqui está uma versão sem nenhum pacote, apenas usando plain \loop
e \repeat
etc.
\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}
Responder3
FWIW, no ConTeXt você pode usar \dorecurse
para repetir algo. Por exemplo:
\dorecurse{10}{Hello world. }
imprimirá Hello world.
10 vezes. O número da iteração atual é armazenado na macro \recurselevel
.
Responder4
No OpTeX, você pode usar \fornum
macro:
\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
A \fornum
macro é totalmente expansível, você pode usar loops aninhados sem abrir ou fechar o grupo.