12

I would like the simplest (in terms of length of characters) way to create a macro that does something or, optionally, does something n times.

In fact, all I want to do is to create something like --------X where the -`s go from 1 to n. I do not want to have to supply 1 to the macro as that is default and the most used case.

So

\dash{X} gives -X
\dash[3]{X} gives ---X
or
\dash{X}[3] gives ---X
or 
\dash{X}{3} gives ---X
or
\dash{3}{X} gives ---X

I don't care about the syntax. Just that it is short and works as intended and should be efficient. I probably don't want to have nested groups used because there would be no point and it would be inefficient, but either way doesn't matter.

I'd like to use as little extra packages as possible unless some package does this well to make it pretty short.

Something like

\newcommand{\dash}[2][1]{\directlua{for i=1,#1 do tex.print('-') end}#2}%

works with LuaLaTeX but tex.print seems to add a space after/before each dash resulting in - - - -X.

CarLaTeX
  • 62,716
  • Since it appears you have problems with the given images, could you please add some more information about intended usage? – egreg Feb 05 '17 at 11:09
  • @egreg huh? I assume you are talking about the spacing? If so, I am simply trying to reduce the space between the symbols(-, +, x, y, or whatever) because I use these things in a large table and can only fit so much information in it. The symbol's touching or closer than normal does not cause any problems in my case but having too much space, like - - X will use far to much space creating a table that won't fit on a page, etc. It's not a huge deal, I can shrink the table... but only so far. Luckily I was able to get a reasonable result with the default space. – AbstractDissonance Feb 05 '17 at 11:16
  • That's caused by math mode automatic spacing: if you use Werner's \dash: fix Werner's code by doing \prg_replicate:nn {#1}{{#2\kern0pt}}#3 – egreg Feb 05 '17 at 11:20

3 Answers3

10

Using xparse (with options):

enter image description here

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\dash}{O{1} O{-} m}{%
  \prg_replicate:nn {#1} {#2}#3
}
\ExplSyntaxOff

\begin{document}

\dash{X}

\dash[2]{X}

\dash[15][{{-}}]{X}

\dash[7][a]{X}

\end{document}

Reference: Repeat characters n times

Werner
  • 603,163
  • Why does using a + cause a space/gap between each one? Same with - one of your examples. Similar to my directlua example. I want to use +++ to have no spaces between them similar to your ------- example. In my code the +'s have almost the a whole space ' ' between them(seems like it). This might just be a property of the characters but the -'s have no space in your example yet for length of 2. When I use your example with a rep of 15 there are no spaces, unlike yours. I need to minimize space between these characters so give me the room I need for other things. – AbstractDissonance Feb 05 '17 at 05:36
  • - is special, since pairs of dashes are turned into an endash, and 3 dashes become an emdash. If you want to remove the spaces between + (say), try with \def\bsp{\def\bsp{$\!$}} \dash[15][\bsp+]{X}. – Werner Feb 05 '17 at 05:53
  • When I use this in my real document I get errors. When I use it in the demo document it works. I put \bsp in the macro you provide, e.g., \bsp#2 and it works as expected. In my code, the only real difference is I'm using the macros in a tikzpicture environment(a matrix). Any idea why it would fail? – AbstractDissonance Feb 05 '17 at 06:17
  • @AbstractDissonance Sorry, no. Not sure what it could be. – Werner Feb 05 '17 at 06:54
  • I believe it is because you are using matrix a matrix of math nodes. (which, one would assume would remove the space but it doesn't...). I tried removing the $ $ but nothing changed. Is there a way to create a new normal symbol like + and - that simply do not have space or is space something that tex adds after the fact? – AbstractDissonance Feb 05 '17 at 07:09
  • @AbstractDissonance: If you use {+} in math mode, the spacing changes to an ordinal (similar to \mathord{+}). However, you might still have a small space on either side by default. By use of \bsp inserts a small backspace between all the elements. Instead of $...$, try \ensuremath{\!}. – Werner Feb 05 '17 at 07:22
  • It didn't help. Not a big deal I suppose. Thanks. – AbstractDissonance Feb 05 '17 at 08:27
  • @Werner \prg_replicate:nn{#1}{{#2\kern0pt}}#3 would do. The \kern is for LuaTeX ignoring braces when looking for ligatures; the braces for avoiding space addition in math mode. – egreg Feb 05 '17 at 11:20
7

Just use one of David Kastrup's good old \replicate-macros that are described here:

http://www.gust.org.pl/projects/pearls/2005p/david-kastrup/bachotex2005-david-kastrup-pearl3.pdf

Example:

\documentclass{article}

\makeatletter
\newcommand\xii[2]{\if#2m#1\expandafter\xii\else\expandafter\@gobble\fi{#1}}
\newcommand\xiii{}\long\def\xiii#1\relax#2{\xii{#2}#1\relax}
\newcommand\replicate[1]{\expandafter\xiii\romannumeral\number\number#1 000\relax}
%
\newcommand\dash[1][1]{\replicate{#1}{-}\@firstofone}
%
% You can avoid consecutive dashes yielding en-dash-ligatures and em-dash-ligatures
% by wrapping the single dash into braces---\hyphendash yields hyphens:
%
\newcommand\hyphendash[1][1]{\replicate{#1}{{-}}\@firstofone}
\makeatother

\begin{document}

\verb|\dash[0]{X}| should yield X and indeed yields \dash[0]{X}

\verb|\dash{X}| should yield -X and indeed yields \dash{X}

\verb|\dash[1]{X}| should yield -X and indeed yields \dash[1]{X}

\verb|\dash[2]{X}| should yield --X and indeed yields \dash[2]{X}

\verb|\dash[3]{X}| should yield ---X and indeed yields \dash[3]{X}

\leavevmode\leaders\hbox{-}\hfill\null

\verb|\hyphendash[0]{X}| should yield X and indeed yields \hyphendash[0]{X}

\verb|\hyphendash{X}| should yield {-}X and indeed yields \hyphendash{X}

\verb|\hyphendash[1]{X}| should yield {-}X and indeed yields \hyphendash[1]{X}

\verb|\hyphendash[2]{X}| should yield {-}{-}X and indeed yields \hyphendash[2]{X}

\verb|\hyphendash[3]{X}| should yield {-}{-}{-}X and indeed yields \hyphendash[3]{X}

\end{document}  

result from compiling the example

If it is only about dashes/hyphens and if you don't want dashes/hyphens to be broken across lines, you can probably also fill a horizontal box of predetermined width with horizontal \leaders:

\documentclass{article}

\makeatletter
\newbox\mytempbox
\newcommand\nobreakhyphendash[1][1]{%
  \begingroup
  \setbox\mytempbox\hbox{-}%
  \vbox{\hbox to#1\wd\mytempbox{\leaders\box\mytempbox\hfill}}%
  \endgroup 
  \@firstofone
}
\makeatother

\begin{document}

\verb|\nobreakhyphendash[0]{X}| should yield X and indeed yields \nobreakhyphendash[0]{X}

\verb|\nobreakhyphendash{X}| should yield {-}X and indeed yields \nobreakhyphendash{X}

\verb|\nobreakhyphendash[1]{X}| should yield {-}X and indeed yields \nobreakhyphendash[1]{X}

\verb|\nobreakhyphendash[2]{X}| should yield {-}{-}X and indeed yields \nobreakhyphendash[2]{X}

\verb|\nobreakhyphendash[3]{X}| should yield {-}{-}{-}X and indeed yields \nobreakhyphendash[3]{X}

\verb|\nobreakhyphendash[15]{X}| should yield {-}{-}{-}{-}{-}{-}{-}{-}{-}{-}{-}{-}{-}{-}{-}X and indeed yields \nobreakhyphendash[15]{X}

\end{document}

result of compiling the example

Ulrich Diez
  • 28,770
5

You might enjoy this generalization:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\pattern}{>{\SplitList{,}}m}
 {
  \ProcessList{#1}{\MakePattern}
 }
\NewDocumentCommand{\MakePattern}{m}
 {
  \MakePatternAux #1 \MakePatternAux
 }
\NewDocumentCommand{\MakePatternAux}{O{1}u{\MakePatternAux}}
 {
  \prg_replicate:nn { #1 } { {#2} }
 }
\ExplSyntaxOff

\begin{document}

\pattern{[3]-,X,-,Y,[5]abc}

$\pattern{[3]-,X,-,Y,[5]+}$

\end{document}

You describe a pattern by a comma separated list of items: X means “print one copy of X”, while [5]Y means “print five copies of Y). The additional braces make TeX into not adding automatic spacing between atoms, because all are treated as ordinary atoms. Items can be more than one token.

enter image description here

egreg
  • 1,121,712