2

To identify an object in many different tabular environments, I want to create a pseudo random hash string with 5 digits (only capital letters). A continuously increasing number is no possibility in this case.

I'm searching for a macro which gives me a different hash string every time I call it. But the value must be the same independent of the compile cycle.

The result should look like within this MWE:

\documentclass{article}%
\usepackage[a4paper,left=10mm,right=10mm,top=10mm,bottom=10mm]{geometry}%

\begin{document}
\begin{tabular}{|c|c|}
\hline
\textbf{HASH} & \textbf{Description} \\ \hline
A4X75 & This is the first Hash \\ \hline
7T0LE & This is the second Hash \\
\hline
\end{tabular}
\end{document}

Tabular

2
  • Unrelated to your question, but why specify 4 columns in a table which only has 2? Commented Feb 17 at 15:59
  • I adapted the MWE to be minimal without useless additional information :)
    – PascalS
    Commented Feb 17 at 16:02

2 Answers 2

6

If you don't use pseudorandom numbers elsewhere,

\documentclass{article}

\ExplSyntaxOn

\sys_gset_rand_seed:n { 0 }% or whatever

\NewExpandableDocumentCommand{\hash}{}
 {
  \int_to_Base:nn { \int_rand:nn { 36 } { 1295 } } { 36 } % two digits
  \__pascals_hash_three:e { \int_to_Base:nn { \int_rand:n { 46655 } } { 36 } } % three digits
 }
\cs_new:Nn \__pascals_hash_three:n
 {
  \prg_replicate:nn { 3 - \tl_count:n { #1 } } { 0 } #1
 }
\cs_generate_variant:Nn \__pascals_hash_three:n { e }

\ExplSyntaxOff

\begin{document}

\begin{tabular}{|c|c|}
\hline
\textbf{HASH} & \textbf{Description} \\ \hline
\hash & This is the first Hash \\ \hline
\hash & This is the second Hash \\
\hline
\end{tabular}

\end{document}

Fixing a seed will allow exact reproduction at every run.

enter image description here

You compute the probability of getting duplicates.

If you need to avoid duplicates because you have too many hashes compared to the number of digits, you lose expandability.

\documentclass{article}

\ExplSyntaxOn

\sys_gset_rand_seed:n { 0 }% or whatever

\NewDocumentCommand{\hash}{}
 {
  \pascals_hash:
 }

\tl_new:N \l__pascals_hash_try_tl
\seq_new:N \g_pascals_hash_used_seq

\cs_new_protected:Nn \pascals_hash:
 {
  % generate a tentative hash
  \tl_set:Ne \l__pascals_hash_try_tl
   {
    \int_to_Base:nn { \int_rand:nn { 36 } { 1295 } } { 36 } % two digits
    \__pascals_hash_three:e { \int_to_Base:nn { \int_rand:n { 46655 } } { 36 } } % three digits 
   }
  % check for duplicate
  \seq_if_in:NVTF \g_pascals_hash_used_seq \l__pascals_hash_try_tl
   {% it's a duplicate, retry
    \pascals_hash:
   }
   {% not a duplicate
    \seq_gput_right:NV \g_pascals_hash_used_seq \l__pascals_hash_try_tl
    \tl_use:N \l__pascals_hash_try_tl
   }
 }

\cs_new:Nn \__pascals_hash_three:n
 {
  \prg_replicate:nn { 3 - \tl_count:n { #1 } } { 0 } #1
 }
\cs_generate_variant:Nn \__pascals_hash_three:n { e }

\ExplSyntaxOff

\begin{document}

\begin{tabular}{|c|c|}
\hline
\textbf{HASH} & \textbf{Description} \\ \hline
\hash & This is the first Hash \\ \hline
\hash & This is the second Hash \\
\hline
\end{tabular}

\end{document}
10
  • Nice, thanks for this fast response! Exactly what I searched for!
    – PascalS
    Commented Feb 17 at 17:01
  • I'm thinking about reducing my digits to 3 or 4 because lack of space. So the probability to create duplicates will increase. Is there an easy way to check for duplicates and in case create a new one? Maybe encapsulated within the hash macro?
    – PascalS
    Commented Feb 18 at 8:47
  • @PascalS Added the code with the check for duplicates
    – egreg
    Commented Feb 18 at 9:10
  • Seems to be what I'm searching for, but at overleaf I got errors. It's not compileable.
    – PascalS
    Commented Feb 18 at 9:17
  • 2
    When \int_rand:n returns 7 (for example) then you doesn't get three digits.
    – wipet
    Commented Feb 18 at 10:11
3

I show what to do with OpTeX. We have no already prepared macro like \_int_to_Base, so we have to use LauTeX primitives \Uchar, \uniformdeviate and we generate six digits in the loop. The probability of the occurrence of a digit in the string is set to 1/3.

\setrandomseed 100 % radom generator initialized, the same for all compilation
\def\randomchar#1#2{\Uchar\numexpr`#1+\uniformdeviate\numexpr`#2-`#1\relax\relax}
\def\randomhash{%
    \fornum 1..6 \do
        {\ifnum\uniformdeviate3 >1 \randomchar 09\else \randomchar AZ\fi}%
}
\def\createhash{\edef\hash{\randomhash}%
   \ifcsname hash:\hash \endcsname \ea\createrandomhash % the hash is already used
   \else \sxdef{hash:\hash}{}\hash \fi
} 

\table{|(\tt)c|c|}{\crl
   \bf HASH    & \bf Description \crl
   \createhash & This is the first Hash \crl
   \createhash & This is the second Hash \crl
}

\bye

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .