8

I'm looking for a way to create a string of random letters and random length. So whenever the command is used I get different strings.

\documentclass[11pt]{article}
\newcommand{\randomstring}{...}

\begin{document}
\randomstring
\randomstring

\end{document}

The out put could be

xkakhiw

or

khaggfpze

I think you got the idea. Could someone give me a hint, where to start?

  • 2
    Any limit to the length of the strings? – egreg Nov 5 '14 at 14:56
  • 1
    A random number between 1 and a maximum determines the length (the maximum is necessary). A random number between 1 and 26 determines a letter (with \ifcase). This process repeated n times gives you the desired string (where n is the length, determined in the first step). I'm not sure, but I think to generate a random number (with pdfTeX at least) there is \pdfuniformdeviate but I don't know its syntax. – Manuel Nov 5 '14 at 15:04
  • @egreg: any number between 1 and 26. – schmendrich Nov 5 '14 at 15:08
11

Using Manuel's idea:

\documentclass{article}

\newcommand{\randomstring}{%
  \expandafter\generatestring\expandafter{\pdfuniformdeviate 26}%
}
\makeatletter
\newcommand{\generatestring}[1]{%
  \expandafter\@alph\expandafter{\number\numexpr1+\pdfuniformdeviate 26}%
  \ifnum#1>\z@
    \expandafter\@firstofone
  \else
    \expandafter\@gobble
  \fi
  {\expandafter\generatestring\expandafter{\number\numexpr#1-1}}%
}
\makeatother

\begin{document}

\randomstring

\randomstring

\randomstring

\edef\foo{\randomstring}\foo

\end{document}

This is fully expandable, as shown by the last call.

enter image description here

With \randomstring we first generate a number between 0 (included) and 26 (excluded), then we call recursively \generatestring with argument decreasing by 1 each time, until 0 is reached.

This works with pdfLaTeX or LuaLaTeX. No expandable way for XeLaTeX.


A version that works with all engines, but is not fully expandable.

\documentclass{article}

\input{random}
\newcount\randomlen
\newcount\randomletter

\makeatletter
\newcommand{\randomstring}{%
  \setrannum{\randomlen}{1}{26}%
  \loop\ifnum\randomlen>\z@
  \setrannum{\randomletter}{1}{26}%
  \@alph{\randomletter}%
  \advance\randomlen\m@ne
  \repeat
}
\makeatother

\begin{document}

\randomstring

\randomstring

\randomstring

\end{document}

enter image description here


A packaged solution. Save the following code as randomstring.sty

\ProvidesPackage{randomstring}[2014/11/06 v. 0.2]

\RequirePackage{ifxetex}

\newcommand{\setrandomstringlength}[1]{%
  \chardef\rstr@length=#1\relax
}
\setrandomstringlength{26}% default

\ifxetex

  \input{random}
  \newcount\randomlen
  \newcount\randomletter

  \newcommand{\rstr@randomstring}[1]{%
    \setrannum{\randomlen}{1}{\rstr@length}%
    \loop\ifnum\randomlen>\z@
      \setrannum{\randomletter}{1}{26}%
      #1%
      \advance\randomlen\m@ne
    \repeat
  }

  \newcommand{\randomstring}{%
    \rstr@randomstring{\@alph{\randomletter}}%
  }
  \newcommand{\defrandomstring}[1]{%
    \@ifdefinable#1{\def#1{}\rstr@randomstring{\rstr@add{#1}}}%
  }
  \newcommand{\rstr@add}[1]{%
    \edef#1{#1\@alph{\randomletter}}%
  }

\else

  \newcommand{\randomstring}{%
    \expandafter\rstr@generate\expandafter{\pdfuniformdeviate \rstr@length}%
  }
  \newcommand{\rstr@generate}[1]{%
    \expandafter\@alph\expandafter{\number\numexpr1+\pdfuniformdeviate 26}%
    \ifnum#1>\z@
      \expandafter\@firstofone
    \else
      \expandafter\@gobble
    \fi
    {\expandafter\rstr@generate\expandafter{\number\numexpr#1-1}}%
  }
  \newcommand{\defrandomstring}[1]{%
    \@ifdefinable#1{\edef#1{\randomstring}}%
  }

\fi

\endinput

Then run with any engine the following file

\documentclass{article}

\usepackage{randomstring}

\begin{document}

\randomstring

\randomstring

\randomstring

\defrandomstring{\foo}\texttt{\meaning\foo}

\setrandomstringlength{1}

\randomstring

\randomstring

\randomstring

\end{document}

Here's one instance of the result. Notice that after \setrandomstringlength{1} the strings have length 1.

The macro \defrandomstring stores the string in the macro passed as argument; if the macro is already defined, an error is raised.

enter image description here

| improve this answer | |
  • Pretty easy syntax for that primitive. I didn't know. – Manuel Nov 5 '14 at 15:24
  • @Manuel Yes, very handy. – egreg Nov 5 '14 at 15:49
  • @egreg: This is great. So I have to switch to lualatex? – schmendrich Nov 6 '14 at 18:27
  • @schmendrich If you're using XeLaTeX, it's possible to do the same, but not in an expandable way. Do you need it? – egreg Nov 6 '14 at 18:28
  • @egreg: I have to admit I have no clue what "expandable way" means :( Could you also provide a solution for xelatex? Why must xelatex have a different solution from the lualatex solution? – schmendrich Nov 6 '14 at 18:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.