12

How can I split the string Hello World! - stored into a macro \def\mystring{Hello Word!} - into a comma-separated list of characters (including spaces) which can be used as argument of a \foreach loop (\foreach \char in {\myCSlist}) in order to loop over each character (as with \foreach \char in {H,e,l,l,o,\space,W,o,r,l,d,!})?

EDIT 1 (Mar 21): Why I want that?

At first, I didn't explain why I want the solution generates a comma-separated list of characters (e.g. \myCSlist) which can be used as argument of a \foreach. It's because I want to create a Tikz \node for each character using a pic. Something like this (from here):

\newcommand{\hsp}{.5}
\tikzset{symbols/.pic={%
    \foreach \s[count=\n from 0] in {\myCSlist}{%
    \pgfmathsetmacro{\myangle}{360*rnd}%
    \node[rotate=\myangle] at (\hsp*\n,0){\s};%
}}}%

First attempt

I tried with the \markletters macro of egreg (using xparse and expl3) but the results seems to be not suitable for looping with foreach.

I changed the result print - of the \markletters macro - from (##1) to ##1,, in order to obtain a comma-separated list, but this also results in a unwanted comma , at the end of the comma-separated list.

Here a M(Non)WE:

\documentclass{article}
\usepackage{tikz}% For the \foreach loop
\usepackage{xparse}

% egreg's \markletters macro : https://tex.stackexchange.com/a/359204/262081 \ExplSyntaxOn \NewDocumentCommand{\markletters}{om} { \IfNoValueTF{#1} { \kessels_markletters:nn { #2 } { \tl_use:N \l_kessels_marked_letters_tl } } { \kessels_markletters:nn { #2 } { \tl_set_eq:NN #1 \l_kessels_marked_letters_tl } } }

\tl_new:N \l_kessels_unmarked_letters_tl \tl_new:N \l_kessels_marked_letters_tl

\cs_new_protected:Nn \kessels_markletters:nn { \tl_set:Nn \l_kessels_unmarked_letters_tl { #1 } \tl_replace_all:Nnn \l_kessels_unmarked_letters_tl { ~ } { \textvisiblespace } \tl_clear:N \l_kessels_marked_letters_tl \tl_map_inline:Nn \l_kessels_unmarked_letters_tl { \tl_put_right:Nn \l_kessels_marked_letters_tl { ##1, } } #2 } \ExplSyntaxOff

\def\mystring{Hello World!}

\begin{document} \markletters[\foo]{\mystring}% \foreach \char in {\foo}{% <\char>% }% \end{document}

This gives the following result:

enter image description here

But I would prefer this result (note the presence of the space between 'Hello' and 'World'):

Enter image description here

zetyty
  • 779

6 Answers6

10

Here's a LuaLaTeX-based solution. It's fully utf8-code aware, i.e., the input string may contain utf8-encoded, as opposed to just ascii-encoded, characters.

The code consists of a Lua function named DoString and a LaTeX utility macros called \DoString, which takes 1 argument -- a character string -- and passes it to the Lua function for further processing.

enter image description here

% !TEX TS-program = lualatex
\documentclass{article}
\directlua{
function DoString ( s )
  for i = 1,string.utflength(s) do 
    tex.sprint ( '<' .. unicode.utf8.sub ( s , i , i ) .. '>' )
  end
end
}
%% Define a LaTeX utility macro:
\newcommand\DoString[1]{\directlua{DoString("#1")}}

\begin{document} \ttfamily \DoString{Hello World!}

\DoString{äöü ÄÖÜ // ß} \end{document}


Addendum to address the OP's follow-up question: To create tikz nodes along the lines suggested in the comment, I suggest you (a) load the luacode package (for the \luaexec macro) and (b) change the \directlua{...} chunk to

\luaexec{
function DoString ( s )
  for i = 1,string.utflength(s) do 
    tex.sprint ( '\\node{' .. unicode.utf8.sub ( s , i , i ) .. '};' )
  end
end
}
Mico
  • 506,678
  • Is there a way to create a Tikz node for each character? I tried something like this: tex.sprint ( '\node{' .. unicode.utf8.sub ( s , i , i ) .. '};' ) but I got an error. At the end I would like to use these nodes in a Tikz pic as shown in this question (see EDIT 4 and look for the \foreach \s[count=\n] in {a,b,c,f} part. I want to replace the {a,b,c,f} list with the output of your macro). – zetyty Mar 21 '22 at 12:41
  • @SylvainRigal - Pleas see the addendum I just posted. A major caveat: While the code suggested in the addendum should compile, I have no idea if it'll actually work for you as I don't use TikZ myself. – Mico Mar 21 '22 at 13:08
  • 2
    The addendum works like a charm! Thanks a lot! – zetyty Mar 21 '22 at 18:27
  • The font seems to be different from the default Latex font. Is there a way to set the default Latex font with your code? – zetyty Mar 22 '22 at 13:08
  • @SylvainRigal - The instruction \ttfamily invokes the default monospaced (aka tele-type) font. If you want the default serif font (called Computer/Latin Modern), simply omit \ttfamily. – Mico Mar 22 '22 at 15:10
  • Just out of curiosity: why put \ttfamily? Is this a Lua coder reflex ;)? – zetyty Mar 22 '22 at 19:47
  • @SylvainRigal - A monospaced font assigns the same width to all characters, including the space character. I thought that using a monospaced font would make reading the output of \DoString marginally easier. It would appear, though, that this attempt was a complete dud, and quite likely even counterproductive. Oh well. – Mico Mar 22 '22 at 20:05
  • 1
    I learn some things, so it wasn't improductive for me. Thank you very much for your reactivity and support! – zetyty Mar 22 '22 at 20:08
9

Here I use a token cycle. No mention was made of macros or groups appearing in the input (only characters and spaces), and so those should be excluded from the input, unless the OP advises on how they should be handled.

If one wishes to then use this list in a for-like loop, one can use \foreachitem from the listofitems package, after reading the comma-separated \mystring into a list.

\documentclass{article}
\usepackage{tokcycle,listofitems}
\Characterdirective{\addcytoks{,#1}}
\Spacedirective{\addcytoks{,#1}}
\makeatletter
\newcommand\markletters[1]{%
  \tokcyclexpress{#1}%
  \expandafter\expandafter\expandafter\def
  \expandafter\expandafter\expandafter\mystring
  \expandafter\expandafter\expandafter
  {\expandafter\@gobble\the\cytoks}%
}
\makeatother
\begin{document}
\markletters{Hello World!}

(\detokenize\expandafter{\mystring})

\readlist\mylist\mystring

\foreachitem\z\in\mylist{$<$\z$>$}

\end{document}

enter image description here

Of course, the whole process could be done more simply inside the token cycle, such that listofitems would not even be needed. And, much to my surprise, if I compile under lualatex, it properly handles UTF-8 input

\documentclass{article}
\usepackage{tokcycle}
\newcommand\markletters[1]{%
  \tokencycle{$<$##1$>$}{}{}{$<$##1$>$}#1\endtokencycle%
}
\begin{document}
\markletters{Hello World! äöü ÄÖÜ // ß}
\end{document}

enter image description here

SUPPLEMENT

Based on OP comments, here is a version (based on the first approach) that handles macros and groups. However, macros requiring arguments would have to be handled carefully, since the comma is being inserted after each token/group.

In this implementation, group content is merely echoed as a single entity. If one wanted group content, subdivided by token, tokcycle can do that, but it is not done in this implementation.

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{tokcycle,listofitems}
\makeatletter
\stripgroupingtrue
\newcommand\markletters[1]{%
  \tokcycle{\addcytoks{,##1}}{\addcytoks{,}\groupedcytoks{##1}}%
    {\addcytoks{,##1}}{\addcytoks{,##1}}{#1}%
  \expandafter\expandafter\expandafter\def
  \expandafter\expandafter\expandafter\mystring
  \expandafter\expandafter\expandafter
  {\expandafter\@gobble\the\cytoks}%
}
\makeatother
\begin{document}
\markletters{Hello World! \today{} is a great day}

(\detokenize\expandafter{\mystring})

\readlist\mylist\mystring

\foreachitem\z\in\mylist{$<$\z$>$}

\mylist[7] is the 7th token

\detokenize\expandafter\expandafter\expandafter{\mylist[14]} is the 14th token \end{document}

enter image description here

  • +1. How might your code need to be adapted to handle utf8-encoded, as opposed to ascii-encoded, characters? – Mico Mar 20 '22 at 21:45
  • 1
    @Mico I think I was mistaken. If I compile under lualatex and use \markletters{Hello World! äöü ÄÖÜ // ß}, I get the correct result. Please see my edited answer. – Steven B. Segletes Mar 20 '22 at 21:55
  • @StevenB.Segletes I completely forgot about macros... That would be very nice indeed. Should I post another question because this one is already quite loaded? Could you advise me because I have never had to make such a big modification to a question that already had so many acceptable answers... – zetyty Mar 21 '22 at 07:34
  • @StevenB.Segletes Is there a way to acces to the character position number in your macro in order to achieve something like this (where \charPos is an integer corresponding to the character position started from 0): \tokencycle{\node at (\charPos,0) {##1};}{}{}{\nodeat (\charPos,0) {##1};}#1\endtokencycle%? At the end I would like to use these nodes in a Tikz pic as shown in this question (see EDIT 4 and look for the \foreach \s[count=\n] in {a,b,c,f} part. I want to replace the {a,b,c,f} list with the output of your macro). – zetyty Mar 21 '22 at 13:01
  • @SylvainRigal As to the situation with macros, the issue (as always) is that some macros take arguments. And arguments typically are provided in groups (curly braces). There is no way to determine on the fly how many arguments a macro takes. Thus, I could save and isolate the macro (sans arguments), but unless you merely regurgitated the input stream without modification, adding commas for example, would break the ability for any execution of the macro. – Steven B. Segletes Mar 21 '22 at 13:48
  • @SylvainRigal As to the issue of character position, the first approach with listofitems already gives you this feature. For example,if you add, to the end of my code, \mylist[7], you will get the 7th token in the list, which is W. – Steven B. Segletes Mar 21 '22 at 13:51
  • 1
    @SylvainRigal Please see the SUPPLEMENT to my answer. Perhaps this gives you more of what you seek. – Steven B. Segletes Mar 21 '22 at 14:09
  • @StevenB.Segletes About character position number. Yes indeed I can acces to the character position with the \zcnt macro provided by listofitems package. Thanks a lot! – zetyty Mar 21 '22 at 18:03
  • @StevenB.Segletes Your first solution using listofitems seems to doesn't work if the string Hello World! is stored into a macro: \def\myFirststring{Hello World!} \markletters{\myFirststring} (see my question EDIT 3). Is there a way to make it works? – zetyty Mar 22 '22 at 10:53
  • 1
    @SylvainRigal In that case, one needs to expand the macro first, as in \def\z{Hello World!}\expandafter\markletters\expandafter{\z}. Alternately, one could build the expansion into the definition of \markletters, with \newcommand\markletters[1]{\expandafter\tokcyclexpress\expandafter{#1}\expandafter\expandafter\expandafter\def \expandafter\expandafter\expandafter\mystring \expandafter\expandafter\expandafter {\expandafter\@gobble\the\cytoks}} – Steven B. Segletes Mar 22 '22 at 14:30
  • @StevenB.Segletes It works fine with your first solution using listofitems but I can't make it works with the version which handles macros AND the one using only tokecycle. Thank you very much for your reactivity and support! – zetyty Mar 22 '22 at 19:57
  • @SylvainRigal By "handles macros", are you asking about where the string is included in a macro \def\z{Hello World!} or are you asking about where the input stream contains a macro \markletters{This is \today}? I would note that the use of listofitems facilitates the use of array lists, allowing use of, for example, \mylist[7]. While tokcycle could be programmed to produce an array, as well, it would remain simpler to use listofitems to index the tokens, recallable by their place in the string. – Steven B. Segletes Mar 22 '22 at 20:44
  • @StevenB.Segletes Sorry, I wasn't clear... You have proposed 3 solutions, 2 using listofitems and one using only tokcycle. Among the 2 solutions with listofitems, one of them works if input stream contains a macro (\markletters{This is \today}). I would like to be able to use a string which is included in a macro (\def\z{Hello World!}) as input with all your 3 solutions. You gave me a way to do it with the first solution using listofitems (the one which don't works if input stream contains a macro) but I'm not able to aplly it to the other 2 solutions... – zetyty Mar 23 '22 at 07:31
  • 1
    @SylvainRigal In the 2nd example, \newcommand\markletters[1]{\tokencycle{$<$##1$>$}{}{$<$##1$>$}{$<$##1$>$}#1\endtokencycle} will handle macros that don't require arguments. It will ignore anything in a group { }. – Steven B. Segletes Mar 23 '22 at 13:32
  • 1
    @SylvainRigal \documentclass{article} \usepackage{tokcycle} \newcommand\markletters[1]{% \tokencycle{\addcytoks{$<$##1$>$}}{\addcytoks{##1}} {\addcytoks{##1}}{\addcytoks{$<$##1$>$}}#1\endtokencycle% } \begin{document} \markletters{Hello World \today! äö\rule{1ex}{1ex}ü ÄÖÜ // ß} \end{document} will handle both macros and groups UNMODIFIED, that is, they will not add < > around them. Further, macro arguments must be placed in groups, or the argument will get messed up with additions of < >. See https://ctan.org/pkg/tokcycle for docs and examples. – Steven B. Segletes Mar 23 '22 at 13:37
7

This can be done using the package xstring. The code also uses \foreach, which is part of tikz but can be loaded with pgffor if your document doesn't use tikz.

enter image description here

\documentclass{article}

\usepackage[T1]{fontenc} % to use accented characters and others \usepackage{xstring} \usepackage{pgffor} % in case you're not using tikz

\newcommand{\markletters}[1]{\StrLen{#1}[\strlen]\foreach \chr in {1,...,\strlen}{$<$\StrChar{#1}{\chr}$>$}}

\begin{document}

\markletters{Hello World!}

\markletters{äöü ÄÖÜ // ß}

\end{document}

Sandy G
  • 42,558
  • +1. How might your code need to be adapted to handle utf8-encoded, as opposed to ascii-encoded, characters? – Mico Mar 20 '22 at 21:45
  • 1
    @Mico: Good thought. This code works fine if you add \usepackage[T1]{fontenc}. I updated my answer. – Sandy G Mar 20 '22 at 21:52
6

Here's a \stringforeach command, with the same syntax as \foreach.

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{geometry}
\usepackage{pgffor}

\makeatletter \newcommand{\stringforeach}{} \def\stringforeach#1#2in{% \def@foreachvariable{#1}% \def@foreachoptions{#2}% @ifnextchar\bgroup{@foreachexplicit}{@foreachimplicit}% } \def@foreachexplicit#1{@stringforeachdo{#1}} \def@foreachimplicit#1{\expandafter@stringforeachdo\expandafter{#1}} \def@stringforeachdo#1{% @transformstringintoclist{#1}% \begingroup\edef\x{% \endgroup \noexpand\foreach \unexpanded\expandafter{@foreachvariable}% \unexpanded\expandafter{@foreachoptions}% in \noexpand@transformedstring }\x } \makeatother

\ExplSyntaxOn

\cs_new_protected:cpn {@transformstringintoclist} #1 { \tl_set:Nn \l_tmpa_tl { #1 } \tl_replace_all:Nnn \l_tmpa_tl { ~ } { \space } \seq_set_split:NnV \l_tmpa_seq { } \l_tmpa_tl \tl_set:cx { @transformedstring } { \seq_use:Nn \l_tmpa_seq { , } } }

\ExplSyntaxOff

\def\mystring{Hello World!}

\begin{document}

\stringforeach \char in \mystring {<\char>}

\stringforeach \char in {Hello World!} {<\char>}

\stringforeach \char [count=\x] in \mystring {<\x=\char>}

\stringforeach \char [count=\x] in {Hello World!} {<\x=\char>}

\end{document}

enter image description here

If you don't need all the \foreach features, it's simpler.

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{geometry}

\ExplSyntaxOn

\NewDocumentCommand{\processtokenlist}{smm} { \IfBooleanTF{#1} {% we have a macro \sylvain_processtl:Vn #2 { #3 } } {% we have an explicit token list \sylvain_processtl:nn { #2 } { #3 } } }

\tl_new:N \l__sylvain_processtl_tl

\cs_new_protected:Nn \sylvain_processtl:nn { \tl_set:Nn \l__sylvain_processtl_tl { #1 } \tl_replace_all:Nnn \l__sylvain_processtl_tl { ~ } { \c_space_tl } \cs_set_protected:Nn __sylvain_processtl_item:n { #2 } \tl_map_function:NN \l__sylvain_processtl_tl __sylvain_processtl_item:n } \cs_generate_variant:Nn \sylvain_processtl:nn { V }

\ExplSyntaxOff

\def\mystring{Hello World!}

\begin{document}

\processtokenlist*{\mystring}{<#1>}

\processtokenlist{Hello World!}{<#1>}

\end{document}

enter image description here

egreg
  • 1,121,712
  • Your solutions seem to not well handle UTF-8 encoding (ß character seems to be not well printed). It was not requested in my original question but pointed out by @Mico in comment. – zetyty Mar 22 '22 at 20:02
  • @SylvainRigal No, currently that's not supported. – egreg Mar 22 '22 at 20:39
  • 1
    @SylvainRigal - The code shown in this answer can handle utf8-encoded characters just fine as long as the document is compiled under LuaLaTeX. (No need to load the fontenc package under LuaLaTeX, though.) – Mico Mar 23 '22 at 08:30
  • I first tried with fontenc AND LuaLaTeX engine but the "ß" was printed as "SS". Indeed, without fontenc it's OK (if compiled under LuaLaTeX). Thanks. – zetyty Mar 24 '22 at 09:40
2

Because we cannot absorb single space by unseparated macro parameter, we must pre-process the given macro by \replspaces macro first. Then you can use \insertcommas which inserts commas between token but not after the last one. Or \insertangles which replaces each token by <token>.

\def\afterfi#1#2\fi{\fi#1}
\def\replspaces#1{\edef#1{\expandafter\replspacesA#1 \end}}
\def\replspacesA #1 #2{#1\ifx\end#2\else { }\afterfi{\replspacesA#2}\fi}
\def\insertcommas#1{\edef#1{\expandafter\insertcommasA#1\end}}
\def\insertcommasA#1#2{#1\ifx\end#2\else,\afterfi{\insertcommasA{#2}}\fi}
\def\insertangles#1{\edef#1{\expandafter\insertanglesA#1\end}}
\def\insertanglesA#1{\ifx\end#1\else<#1>\expandafter\insertanglesA\fi}

% test:

\def\mystring{Hello World!}

\replspaces\mystring \insertcommas\mystring \meaning\mystring % macro:-> H,e,l,l,o, ,W,o,r,l,d,!

\def\mystring{Hello World!}

\replspaces\mystring \insertangles\mystring \meaning\mystring % macro:-> <H><e><l><l><o>< ><W><o><r><l><d><!>

\bye

Edit Your first ask was: how to create a macro H,e,l,l,o, ,w,o,r,d,! from the macro Hello World!. I answered correctly.

Now, your second ask is: how to use such macro in \foreach from Tikz. I don't know how to set effectively the expanded parameter to a somewhat impractical \foreach from Tikz (you can use \expanded{\unexpanded {\foreach ...}{\mystring}} but it seems horrible). It should be better not to use \foreach from Tikz at all and define your own \myforeach:

\def\replspaces#1{\edef#1{\expandafter\replspacesA#1 \end}}
\def\replspacesA #1 #2{#1\ifx\end#2\else { }\afterfi{\replspacesA#2}\fi}
\def\myforeach#1{\expandafter\myforeachA#1\end}
\def\myforeachA#1{\ifx\end#1\else\body{#1}\expandafter\myforeachA\fi}

\def\body#1{<#1>} \def\mystring{Hello World!}

\replspaces\mystring \myforeach\mystring % prints: <H><e><l><l><o>< ><W><o><r><l><d><!>

\bye

wipet
  • 74,238
  • If I do something like this \replspaces\mystring \insertcommas\mystring \foreach \char in {\mystring}{<\char>}, it doesn't loop over each character in the string, I just get this: <H,e,l,l,o, ,W,o,r,l,d,!>. Am I doing something wrong? – zetyty Mar 22 '22 at 08:04
  • My first ask was: How to create a macro H,e,l,l,o, ,w,o,r,d,! from the macro Hello World! which can be used as an \foreach argument? I'm sincerely sorry if it was not clear. I'm sure there are many other way to do it but the \foreach syntax is easy to use for me and I can acces easily to the loop integer or start it from 0. Anyway, your solution works fine thank you. – zetyty Mar 23 '22 at 10:07
  • @SylvainRigal The problem is that the parameter for Tikz's \foreach must be expanded before the \foreach is processed. But you cannot use single \expandafter because the parameter is due to the inappropriately \foreach syntax positioned at the very back. I don't want to study the 1400 pages manual of Tikz in order to know, how to do it using Tikz concept. It is more simple for me to write my own \foreach macro. I hoped that you know how to expand the parameter for \foreach from Tikz if you want to use it and that this is not the main problem asked here. – wipet Mar 23 '22 at 15:18
  • You're right is not the main problem here... But I disturb you again because I tried to used your myforeach with this: \newcounter{cnt}\setcounter{cnt}{-1}\def\body#1{\stepcounter{cnt}\pgfmathsetmacro{\myangle}{360*rnd}\pgfmathsetmacro{\mystep}{\thecnt}\pgfmathsetmacro{\myangle}{360*rnd}\node[rotate=\myangle] at (\hsp*\mystep,0){#1};}% but I got the following error: ! Undefined control sequence. \replspacesA ...->#1\ifx \end #2\else { }\afterfi{\replspacesA #2}\fi. – zetyty Mar 24 '22 at 10:28
  • Undefined control sequence \afterfi? Maybe there is not copied the definition of \afterfi from the firs line of my first example. Ii is my mistake that I didn't copied it from my first example to the second. – wipet Mar 24 '22 at 14:53
  • I'm so silly, I didn't seen the \def\afterfi#1#2\fi{\fi#1} in your first exemple sorry. So your foreach works like a charm to generate my Tikz pic, I will update my question with this result... Thans for your support! – zetyty Mar 24 '22 at 14:59
1

Since you're already using PGF/TikZ you might as well use the parser module that comes with it.

We'll define a parser char parser that does something (/char parser/do) with each letter, for this we need three actions:

  1. the one for the space (it's special),
  2. the one for every other character and
  3. for the end of the parsing.

I'm using a @-protected macro \charparser@stop to end the parsing since any other letter (like ;) could show up in the text that shall be parsed.

The action for every other character is done by defining an action for an unknown letter – unknown except for the space or for the ending. The parser would actually raise an error in that case but we can set char parser/silent=true.

And then it's just a question about what you want to do with every letter.

We can place a node for it:

\tikz[
  /char parser/do/.code={\node[rotate=360*rnd] at (\charparsercount,0) {#1};},
  /char parser/parse={Hello World! äöüßÄÖÜ}
]{}

Yes, the parser increments a macro (not a counter) \charparsercount. The key do will be used with the found character.

We can also make a comma-separated list and use it with \foreach:

\tikz[
  /char parser/list=\myList,
  /char parser/parse={Hello World! äöüßÄÖÜ}%
]
\foreach \s[count=\n from 0] in \myList
  \node[rotate=360*rnd] at (\n,0) {\s};

If you have the to-be-parsed text in a macro just use /.expand once:

\newcommand*\myText{Hello World! äöüßÄÖ}
/char parser/parse/.expand once=\myText

Code

% use lualatex
\documentclass[tikz]{standalone}
\newcommand*\charparserset{\pgfqkeys{/char parser}}
\usepgfmodule{parser}
\pgfparserdefunknown{char parser}{initial}{%
  \pgfkeysalso{/char parser/do/.expand once=\pgfparserletter,/char parser/next}}
\pgfparserdef{char parser}{initial}{blank space}{%
  \pgfkeysalso{/char parser/do=\space,/char parser/next}}
\pgfparserset{char parser/silent=true}
\makeatletter
\pgfparserdef{char parser}{initial}\charparser@stop{%
  \pgfkeysalso{/char parser/final/.try}\pgfparserswitch{final}}
\charparserset{parse/.code={%
    \charparserset{init}%
    \pgfparserparse{char parser}#1\charparser@stop}}
\makeatother
\charparserset{
  init/.code=\def\charparsercount{0},
  next/.code=\edef\charparsercount{\the\numexpr\charparsercount+1\relax},
  list/.style={
    /char parser/final/.append code=\pgfkeysgetvalue{/char parser/@list}#1,
    /char parser/@list/.initial=,
    /char parser/do/.style={
      /char parser/@list/.append={##1},
      /char parser/do/.style={
        /char parser/@list/.append={,####1}}}},
  do/.code={#1}}
\begin{document}
\tikz[
  x=5mm,
  /char parser/do/.code={\node[rotate=360*rnd] at (\charparsercount,0) {#1};},
  /char parser/parse={Hello World! äöüßÄÖÜ}
]{}
\tikz[
  x=5mm,
  /char parser/list=\myList,
  /char parser/parse={Hello World! äöüßÄÖÜ}%
]
\foreach \s[count=\n from 0] in \myList
  \node[rotate=360*rnd] at (\n,0) {\s};
\end{document}

Output

enter image description here

Qrrbrbirlbel
  • 119,821