I am playing with LuaLaTeX substitutions, trying to find a way to replace a string within a macro with random characters of the same length.

The chickenize package offers the randomchars function which does this for an entire paragraph. However, I cannot get this to work on just the argument of the TeX macro, and get either errors or nothing when trying to create a macro like:


  • Do uppercase and lowercase have to be respected? Or should it be all uppercase, all lowercase, or should the case status of letters be random as well (presumably 50-50, right)? Should whitespace be preserved as such? What about any digits in the string: Should they be replaced with other, randomly chosen digits? Please advise.
    – Mico
    Jan 30 at 13:52
  • 1
    Any character in unicode is fine, but whitespace should be respected (so abcd can be replaced with !RX? )
    – luaplaying
    Jan 30 at 13:56
  • Imho, this is a better question for a Lua community, where you'd most likely get the broader audience. Afterwards it's just tex.print the results.
    – Skillmon
    Jan 30 at 14:43
  • Perhaps something along these lines: tex.stackexchange.com/questions/450795/…. Also, "of same length" I presume you mean same number of characters, and not same textual width? Jan 30 at 17:00
  • I should note my above comment is an alternative to lua. Jan 30 at 18:00

1 Answer 1


Here you go. Note that the input and output characters could be (almost) arbitrary utf8-encoded characters. (On output, it's your job to verify that the output characters are indeed present in the font that's in use.) If the characters are TeX-special -- say, & and $ -- be sure to escape them as \\& and \\$, etc. Whitespace in the input string is preserved, but punctuation characters aren't given any preferential treatment.

enter image description here

% !TEX TS-program = lualatex
\usepackage{luacode} % for 'luacode' environment and '\luastring' macro
function rndstring ( inputstring )
  local outputstring, choices, mm, nn
  mm = unicode.utf8.len(inputstring) -- no. of utf8-encoded characters in input string

  -- Place candidate replacement characters in a Lua table:
  choices = { 
     "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", 
     "\\#", "\\$", "\\%", "\\%", "\\&", "\\_", "\\textbackslash{}",
     "*", "+", "-", "/", "(", ")", "[", "]", "\\{", "\\}",
     "<", "=", ">", "?", "@", "\\textasciitilde{}",
     "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", 
     "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", 
     "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", 
     "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"
  -- Number of rows in 'choices' table
  nn = #choices 

  -- Generate the outputstring in a 'for' loop:
  outputstring = ""
  for i = 1 , mm do
     if unicode.utf8.sub ( inputstring , i , i ) == " "  then
         outputstring = outputstring .. " " -- preserve space char.
     else -- choose a new char randomly from 'choices' table
         outputstring = outputstring .. choices[ math.random ( nn ) ]

   return ( outputstring )

%% Define a LaTeX macro to invoke the Lua function

%% test strings to feed to '\rndstring':
\newcommand\stringA{Hello World}
\newcommand\stringB{Hello Владимир öäüß}
\newcommand\stringC{Once upon a time, there was ...}

\ttfamily % optional



  • Why not use #choices to get the number of choices in the table?
    – Skillmon
    Jan 30 at 23:33
  • @Skillmon - Good question! :-) I guess it's because of an old (aquired) habit of mine: In general, one should not assume that the two methods provide the same result. However, after about 10 seconds of thought, it's clear to me too that for the Lua table at hand, the two methods must provide the same result, since there are no "gaps" in this table. Indeed, I rely on this result implicitly later on, when I select a table entry randomly via choices[ math.random ( nn ) ]. I'll go ahead and fix this issue in the code.
    – Mico
    Jan 31 at 0:34
  • 1
    I knew about the peculiarities of table access in Lua with the # operator (just came to the same conclusion as you here, in that it is the same if the table assignment is done this way).
    – Skillmon
    Jan 31 at 6:13
  • 1
    magnificent, thank you!
    – luaplaying
    Jan 31 at 16:49

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.