Here's an implementation with l3regex
:
\documentclass{article}
\usepackage{xparse,l3regex}
\ExplSyntaxOn
\NewDocumentCommand\makeBlocks{mm}
{
\geoff_makeblocks:nn { #1 } { #2 }
}
\tl_new:N \l_geoff_blocks_input_tl
\cs_new_protected:Npn \geoff_makeblocks:nn #1 #2
{
\tl_set:Nn \l_geoff_blocks_input_tl { #2 }
%\tl_reverse:N \l_geoff_blocks_input_tl
\regex_replace_all:nnN { (.{0,#1}) } { \1 \c{,} } \l_geoff_blocks_input_tl
\regex_replace_once:nnN { \c{,} \c{,} \Z } { } \l_geoff_blocks_input_tl
%\tl_reverse:N \l_geoff_blocks_input_tl
\tl_use:N \l_geoff_blocks_input_tl
}
\ExplSyntaxOff
\begin{document}
\makeBlocks{3}{abcdef}
\makeBlocks{3}{abcdefg}
\makeBlocks{3}{abcdefghi}
\makeBlocks{5}{aaaaabbbbbccccc}
\end{document}

This counts starting from the left. If you want to start counting from the right, just reverse twice the token list, by uncommenting the two \tl_reverse:N
lines. Here's what you'd get:

If you want a normal space between blocks, just change the two \regex
lines into
\regex_replace_all:nnN { (.{0,#1}) } { \1 \cS\ } \l_geoff_blocks_input_tl
\regex_replace_once:nnN { \cS. \cS. \Z } { } \l_geoff_blocks_input_tl
A “full featured” macro that starts either from left or from right (this with the *
-variant) and accepts the separator as optional argument (default a space).
\documentclass{article}
\usepackage{xparse,l3regex}
\ExplSyntaxOn
\NewDocumentCommand\makeBlocks{s O{~} m m }
{
\IfBooleanTF{#1}
{
\geoff_makeblocks:nnnn { #2 } { #3 } { #4 } { \__geoff_from_right: }
}
{
\geoff_makeblocks:nnnn { #2 } { #3 } { #4 } { }
}
}
\tl_new:N \l_geoff_blocks_input_tl
\tl_new:N \l_geoff_block_separator_tl
\cs_new_protected:Npn \geoff_makeblocks:nnnn #1 #2 #3 #4
{
\tl_set:Nn \l_geoff_block_separator_tl { #1 }
\tl_set:Nn \l_geoff_blocks_input_tl { #3 }
#4 % this will be nothing or \tl_reverse:N \l_geoff_blocks_input_tl
% search blocks of #2 tokens and put the separator after them
\regex_replace_all:nnN
{ (.{#2}) } % search
{ \1 \u{l_geoff_block_separator_tl} } % replace
\l_geoff_blocks_input_tl % in this list
% if the number of tokens is a multiple of #2, one too much
% separator is inserted, remove it
\regex_replace_once:nnN
{ \u{l_geoff_block_separator_tl} \Z } % search
{ } % replace
\l_geoff_blocks_input_tl % in this list
#4
\tl_use:N \l_geoff_blocks_input_tl
}
\cs_new:Npn \__geoff_from_right:
{
\tl_reverse:N \l_geoff_blocks_input_tl
}
\ExplSyntaxOff
\begin{document}
From left: \makeBlocks{3}{abcdef}
From left: \makeBlocks{3}{abcdefg}
From right: \makeBlocks*{3}{abcdefgh}
With different separator: \makeBlocks[ x ]{3}{abcdefghi}
With different number: \makeBlocks{5}{aaaaabbbbbccccc}
\end{document}

\makeBlocks
handle the content if the number doesn't divide the length of the string, as in\makeBlocks{4}{abcdefghi}
?