Repetir caracteres n veces

Repetir caracteres n veces

Quería crear un nuevo comando, que me permita hacer repeatlo que charactersquiera n times. Después de buscar e intentar un poco, se me ocurrió esto:

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

Había un espacio extraño después del comando en el PDF resultante, así que agregué los símbolos de comentario %y luego desapareció.

Mi pregunta es: ¿Existe una forma mejor de hacer esto, que sea tan fácil de entender como ésta, preferiblemente sin introducir muchas dependencias?

Uno sin él multidotambién está bien, si no es demasiado complicado, o si puedes explicarlo para que ya no sea complicado. Supongo que usar multidopara tal cosa está bien, ya que su nombre significa hacer algo varias veces, pero no estoy seguro de haber elegido la forma más fácil y limpia de hacerlo.

Tenga en cuenta que mis soluciones agregan un espacio menos que elementos al pdf. La forma de restar uno me parece sospechosamente detallada.

Tengo dos versiones funcionando ahora:

El 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}{.....}{\ }
}

El 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]{.....}{\ }
}

No sé si uno tiene alguna ventaja sobre el otro. Quizás también haya una mejor manera de eliminar el último espacio en blanco o carácter de separación, en lugar de hacer una iteración menos y escribir solo los caracteres para repetir nuevamente sin el separador. Introduje el separador porque pensé que podría ser útil y es solo un tercer parámetro.

Respuesta1

Sin paquetes:

\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 qué el grupo? Permite llamadas anidadas.

ingrese la descripción de la imagen aquí

Si solo quieres repetir un personaje:

\documentclass{article}

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

\begin{document}

\myrepeat{4}{x}

\end{document}

Como bien comenta Ulrich Diez, este código no permitiría un registro del contador como número de repeticiones; Para respaldar esto, se ofrece una versión un poco más complicada.

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

\romannumeraldesencadena el primero \numberque expande el segundo; si tenemos, digamos, 4 a medida que #1obtenemos sucesivamente (donde denota una ficha de espacio

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

Si, en cambio, tenemos \count27as #1y \count27mantenemos el valor 4, obtenemos

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

Si tenemos \foo(un registro contador con nombre), manteniendo nuevamente el valor 4, tenemos

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

Por lo tantodoscasos de \numberson necesarios para cubrir el tercer caso. Esto aprovecha el hecho de que un espacio finaliza la búsqueda de un número "explícito" y luego se ignora (el token de espacio no se ignora en el tercer caso, después de la expansión del segundo \numbertoken).

Si también quieres poner un texto entre las repeticiones, el primer método es muy sencillo: simplemente empieza el bucle en 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

(No llames a esto con cero repeticiones).

Una solución diferente con recursividad y la vieja idea de \romannumeral#1000que produce una larga cadena de m que podemos consumir una a la 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}

ingrese la descripción de la imagen aquí

La recursividad consumedostokens a la vez, para distinguir si solo le queda un paso más por hacer. El segundo token se devuelve cuando se reinicia la recursividad.


Sin embargo, esto es sólo para estudio. En una aplicación del mundo real lo haría

\usepackage{xparse}

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

ser llamado como \myrepeat[-]{4}{x}recibir

xxxx

y \myrepeat{3}{A}para conseguir

aaa

Respuesta2

Aquí hay una versión sin ningún paquete, solo usando simple \loop, \repeatetc.

\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}

ingrese la descripción de la imagen aquí

Respuesta3

FWIW, en ConTeXt puedes usarlo \dorecursepara repetir algo. Por ejemplo:

\dorecurse{10}{Hello world. }

imprimirá Hello world.10 veces. El número de iteración actual se almacena en la macro \recurselevel.

Respuesta4

En OpTeX, puedes usar \fornummacro:

\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

La \fornummacro es totalmente ampliable, puede utilizar bucles anidados sin abrir ni cerrar el grupo.

información relacionada