Security code generator

The problem comes with the accented characters, unless you use XeLaTeX or LuaLaTeX. Here's a solution that works for all engines (but UTF-8 is required anyway.

The input is stringified and then the various bits are compare to the codes established in the preamble. If the character happens to be a UTF-8 prefix, it is put aside and the next one is added to it for the comparison.

\documentclass{article}
\usepackage{ifxetex}

\ifxetex\else
  \usepackage[utf8]{inputenc}
\fi

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\namekoda}{m}
 {
  \ziga_namekoda:n { #1 }
 }

\cs_new_protected:Nn \ziga_namekoda:n
 {
  \tl_set:Nx \l__ziga_namekoda_input_tl { \tl_to_str:n { #1 } }
  \tl_replace_all:Nnn \l__ziga_namekoda_input_tl { ~ } { | }
  \tl_clear:N \l_ziga_namekoda_output_tl
  \tl_clear:N \l__ziga_namekoda_current_tl
  \tl_map_inline:Nn \l__ziga_namekoda_input_tl
   {
    \__ziga_namekoda_step:n { ##1 }
   }
  \tl_use:N \l_ziga_namekoda_output_tl
 }

\cs_new_protected:Nn \__ziga_namekoda_step:n
 {
  \str_case_x:nnF { #1 }
   {
    { \char_generate:nn { "C3 } { 12 } } { \__ziga_namekoda_add:n { #1 } }
    { \char_generate:nn { "C4 } { 12 } } { \__ziga_namekoda_add:n { #1 } }
    { \char_generate:nn { "C5 } { 12 } } { \__ziga_namekoda_add:n { #1 } }
   }
   { \__ziga_namekoda_go:n { #1 } }
 }

\cs_new_protected:Nn \__ziga_namekoda_add:n
 {
  \tl_put_right:Nn \l__ziga_namekoda_current_tl { #1 }
 }
\cs_new_protected:Nn \__ziga_namekoda_go:n
 {
  \__ziga_namekoda_add:n { #1 }
  \tl_put_right:Nx \l_ziga_namekoda_output_tl
   {
    \str_case:VV \l__ziga_namekoda_current_tl \c_ziga_namekoda_codes_tl .
   }
  \tl_clear:N \l__ziga_namekoda_current_tl
 }
\cs_generate_variant:Nn \str_case:nn { VV }

\tl_const:Nx \c_ziga_namekoda_codes_tl
 {
  { \tl_to_str:n { a } } { 1 }
  { \tl_to_str:n { A } } { 1 }
  { \tl_to_str:n { b } } { 2 }
  { \tl_to_str:n { B } } { 2 }
  { \tl_to_str:n { c } } { 3 }
  { \tl_to_str:n { C } } { 3 }
  { \tl_to_str:n { č } } { 4 }
  { \tl_to_str:n { Č } } { 4 }
  { \tl_to_str:n { d } } { 5 }
  { \tl_to_str:n { D } } { 5 }
  { \tl_to_str:n { e } } { 6 }
  { \tl_to_str:n { E } } { 6 }
  { \tl_to_str:n { f } } { 7 }
  { \tl_to_str:n { F } } { 7 }
  { \tl_to_str:n { g } } { 8 }
  { \tl_to_str:n { G } } { 8 }
  { \tl_to_str:n { h } } { 9 }
  { \tl_to_str:n { H } } { 9 }
  { \tl_to_str:n { i } } { 10 }
  { \tl_to_str:n { I } } { 10 }
  { \tl_to_str:n { j } } { 11 }
  { \tl_to_str:n { J } } { 11 }
  { \tl_to_str:n { k } } { 12 }
  { \tl_to_str:n { K } } { 12 }
  { \tl_to_str:n { l } } { 13 }
  { \tl_to_str:n { L } } { 13 }
  { \tl_to_str:n { m } } { 14 }
  { \tl_to_str:n { M } } { 14 }
  { \tl_to_str:n { n } } { 15 }
  { \tl_to_str:n { N } } { 15 }
  { \tl_to_str:n { o } } { 16 }
  { \tl_to_str:n { O } } { 16 }
  { \tl_to_str:n { p } } { 17 }
  { \tl_to_str:n { P } } { 17 }
  { \tl_to_str:n { r } } { 18 }
  { \tl_to_str:n { R } } { 18 }
  { \tl_to_str:n { s } } { 19 }
  { \tl_to_str:n { S } } { 19 }
  { \tl_to_str:n { š } } { 20 }
  { \tl_to_str:n { Š } } { 20 }
  { \tl_to_str:n { t } } { 21 }
  { \tl_to_str:n { T } } { 21 }
  { \tl_to_str:n { u } } { 22 }
  { \tl_to_str:n { U } } { 22 }
  { \tl_to_str:n { v } } { 23 }
  { \tl_to_str:n { V } } { 23 }
%  { \tl_to_str:n { x } } {  }
%  { \tl_to_str:n { X } } {  }
%  { \tl_to_str:n { y } } {  }
%  { \tl_to_str:n { Y } } {  }
  { \tl_to_str:n { z } } { 24 }
  { \tl_to_str:n { Z } } { 24 }
  { \tl_to_str:n { ž } } { 25 }
  { \tl_to_str:n { Ž } } { 25 }
  { \tl_to_str:n { _ } } { 26 }
  { \tl_to_str:n { | } } { 26 }
}
\ExplSyntaxOff

\begin{document}

\namekoda{Žiga Lausegger}

\namekoda{ŽIGA LAUSEGGER}

\namekoda{Marko Milič}

\end{document}

The output is the same for all engines.

enter image description here

Explanation

You seem to want the Slovenian alphabet, with č, š and ž (other common foreign characters like ć might be easily accommodated).

The main problem is that the characters with the diacritic are not a single byte in UTF-8 and that pdflatex emulates UTF-8 input by reading the “prefix” which will look at the next byte(s).

In the case of Slovenian, the prefixes are bytes 0xC3, 0xC4 and 0xC5. Examining one character at a time will not work, so we need a different strategy.

The main macro works by making a string representation of the input. Then it will go one character at a time comparing it with a given list of cases; if the character is a prefix, it is just stored and the next one is read, forming a two-byte sequence that's compared with the given list.

The preloaded list works in a similar way: each character is made into a one or two byte string, and a token list useful as the second argument to \str_case:nn is prepared.

So, what happens to the name Žiga? The string formed from it will contain the bytes

C5 BD 69 67 61

When the string is mapped, the first byte will be recognized as a prefix, so put aside and the next byte will be added to it; then the constructed token list is compared with \str_case:nn (in the variant \str_case:VV) and so the number 25 is returned, followed by a period. The tokens 25. are stored in the token list for the output and the next character is examined. Repeat until end.

Finally the token list for the output is delivered.

In case XeLaTeX or LuaLaTeX are used, the question is simpler, because UTF-8 characters are converted to a single entity when the file is read in, so the step with the check for prefixes will never happen, but the output will be the same nonetheless.


I have modified egreg answer from How to repeat over all characters in a string? for your problem

\documentclass{article}
\usepackage{xstring}

\makeatletter
\newcommand{\koda}[1]{%
   \@tfor\next:=#1\do{\myList{\next}}%
}
\makeatother

\newcommand{\myList}[1]{%
    \IfEqCase{#1}{%
       {a}{1.}%
       {b}{2.}%
       {c}{3.}%
       {č}{4.}%
       {d}{5.}%
       {e}{6.}%
       {f}{7.}%
       {g}{8.}%
       {h}{9.}%
       {i}{10.}%
       {j}{11.}%
       {k}{12.}%
       {l}{13.}%
       {m}{14.}%
       {n}{15.}%
       {o}{16.}%
       {p}{17.}%
       {r}{18.}%
       {s}{19.}%
       {š}{20.}%
       {t}{21.}%
       {u}{22.}%
       {v}{23.}%
       {z}{24.}%
       {ž}{25.}%
       {_}{26.}%
       { }{26.}%
    % you can add more cases here as desired
   }[\PackageError{koda}{Undefined option to koda: #1}{}]%
}%


\begin{document}
    \koda{name_surname}
\end{document}

It doesn't seem to handle space correctly, so i inserted _ instead, but it's sommething :)

enter image description here

EDIT: I searched a little and remembered where I had the answer from


You can do this using \def to recursively extract the characters in the name:

\documentclass{article}
\usepackage{xstring}
\usepackage[utf8]{inputenc}

\newcommand{\realkoda}[1]{%
\IfEqCase{#1}{%
    {a}{1.}%
    {b}{2.}%
    {c}{3.}%
    {č}{4.}%
    {d}{5.}%
    {e}{6.}%
    {f}{7.}%
    {g}{8.}%
    {h}{9.}%
    {i}{10.}%
    {j}{11.}%
    {k}{12.}%
    {l}{13.}%
    {m}{14.}%
    {n}{15.}%
    {o}{16.}%
    {p}{17.}%
    {r}{18.}%
    {s}{19.}%
    {š}{20.}%
    {t}{21.}%
    {u}{22.}%
    {v}{23.}%
    {z}{24.}%
    {ž}{25.}%
    {_}{26.}%
    {S}{26.}%
    % you can add more cases here as desired
}[\PackageError{koda}{Undefined option to koda: #1}{}]%
}%
\makeatletter
\def\runningkoda#1#2@{\ifx#1!\relax\else\realkoda{#1}\ifx#2!\relax\else\runningkoda#2@\fi\fi}
\def\prekoda#1 #2@{\ifx#2\relax\relax\runningkoda#1!@\else\runningkoda#1S#2!@\fi}
\newcommand\koda[1]{\prekoda#1 @}
\makeatother

\begin{document}

Name surname: \koda{name surname}

Name\_surname: \koda{name_surname}

\end{document}

The idea is that \koda calls \runningkoda with some stray characters !@ at the end and \runningkoda uses these to test whether or not it is at the end of the character list. If not then #1 is given to the original \koda macro, now called \realkoda, and #2@ is given as the argument to \runningkoda. We have to give @ each time because the previous @ is gobbled up each time \runningkoda is used.

To cope with spaces in the names is a little trickier but uses the same idea. I "preprocess" the name with \prekoda to sort the name into the bit before the space and the bit after. The space is replaced with an S and \realkoda recognises this and replaces it with the "code" 26. Currently this copes with only one space in the name. If necessary, it should/might be possible to allow multiples spaces by using \SplitArgument from xparse.

Here is the output:

enter image description here

My macro will give an error if you pass it an empty string.

Tags:

Macros