11

I have this primitive latex generator for generating a document number from customer's name, white space and surname:

\newcommand{\koda}[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}{}]%
}%

Which I use like this inside a document

\koda{n}\koda{a}\koda{m}\koda{e}\koda{_}\koda{s}\koda{u}\koda{r}\koda{n}\koda{a}\koda{m}\koda{e}

And this will produce a code in which custommer's letters are represented by their alphabet order numbers (underscore and whitespace are added to the alphabet). The code looks like this: enter image description here

This works completely fine, but I would need a simpler mechanism to input name and surname of the customer and get a same document code. Can this be achieved using \newcommand{}{}? Problem is because not every customer has same name length and therefore I don't know how to define the number of expected inputs...

I wish to use just something like \koda{name surname} to get the code.

2
  • 7
    Hopefully not really security codes with this kind of regularity!
    – cfr
    Jun 1, 2017 at 12:45
  • @cfr This is not intended for a security. How would you secure the document?
    – 71GA
    Jun 1, 2017 at 15:33

3 Answers 3

5

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

1
  • I like this answer the most because of it's simplicity. @egreg's answer is a bit too complicated for me. I just learned what \makeatletter does... =)
    – 71GA
    Jun 1, 2017 at 16:50
7

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.

4
  • Why \ifxetex and not \sys_if_engine_xetex?
    – TeXnician
    Jun 1, 2017 at 13:15
  • @TeXnician Because that's at user level
    – egreg
    Jun 1, 2017 at 13:16
  • This answer is very complex and needs some explanation.
    – 71GA
    Jun 1, 2017 at 15:44
  • @71GA You'll have comments soon.
    – egreg
    Jun 1, 2017 at 15:46
4

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.

2
  • Try \koda{česko}
    – egreg
    Jun 1, 2017 at 13:18
  • @egreg Yes, I agree, it doesn't work with unicode, even if you add extra branches for them in the \ifEqCase statement in \realkoda. I tested only the code in the MWE...
    – user30471
    Jun 1, 2017 at 21:39

You must log in to answer this question.

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