# Looping over macro arguments with spaces and building partial commands

\documentclass{article}

\usepackage{ruby}

\newcommand{\strsymbol}{\large\bfseries∗}
\newcommand{\unssymbol}{\large·}
\newcommand{\str}[1]{\textbf{\ruby{#1}{\strsymbol}}{}}
\newcommand{\uns}[1]{\ruby{#1}{\unssymbol}{}}

\begin{document}

\uns{A} \uns{po}\uns{ly}\str{syl}\uns{la}\uns{ble} \uns{should} \uns{be} \str{fun} \uns{to} \uns{de}\str{fine}.

\end{document}


It generates output like this:

(Well I use nicer fonts and symbols, but you get the idea).

As you can see, that code is quite unwieldly. Ideally I'd like some function to accept an argument like this:

\stress{A po-ly*syl*la-ble should be *fun* to de*fine*.}


In fact, the working example up there wasn't written by hand; it's the output of some ugly Emacs Lisp code I wrote to convert the nicer argument format. It just loops over the characters handling the several different cases (*, -, Unicode alphanumerics, and space/punctuation), keeping track of state to start and end the Latex commands accordingly.

I'm totally new to Tex programming, and was wondering whether a Latex solution is possible. I have to use Xetex because of reasons. My attempts didn't get very far; I can't loop over strings with \@tfor because it eats inner whitespace, and even if I could, I don't know how to write a command piecemeal spanning many loop interactions (like \ruby{}). I saw the answer about Expandable 'character scanning' command that preserves spaces , but I couldn't even being to figure out how one should modify the sample code to implement something like this.

What's the best approach to write a Latex macro accepting an argument like this?

With l3regex:

\documentclass{article}

\usepackage{ruby}
\usepackage{textcomp}
\usepackage{xparse,l3regex}

\newcommand{\strsymbol}{\large\bfseries\textasteriskcentered}
\newcommand{\unssymbol}{\large\textperiodcentered}
\newcommand{\str}[1]{\textbf{\ruby{#1}{\strsymbol}}{}}
\newcommand{\uns}[1]{\ruby{#1}{\unssymbol}{}}

\ExplSyntaxOn
\NewDocumentCommand{\stress}{m}
{
\leoboiko_stress:n { #1 }
}

\tl_new:N \l_leoboiko_stress_sentence_tl

\cs_new_protected:Nn \leoboiko_stress:n
{
\tl_set:Nn \l_leoboiko_stress_sentence_tl { #1 }
% change *<syllable>* into -*<syllable>*-
\regex_replace_all:nnN { \*(.*?)\* } { -*\1*- } \l_leoboiko_stress_sentence_tl
% change <space> into -<space>
\regex_replace_all:nnN { \s } { -\cS\  } \l_leoboiko_stress_sentence_tl
% change <space> into <space>-
\regex_replace_all:nnN { \s } { \cS\ - } \l_leoboiko_stress_sentence_tl
% add - at either end
\regex_replace_once:nnN { \A (.*) \Z } { - \1 - } \l_leoboiko_stress_sentence_tl
% normalize -- to -
\regex_replace_all:nnN { \-\- } { \cO\- } \l_leoboiko_stress_sentence_tl
% change -<letters>- into \uns{letters}-
\regex_replace_all:nnN { \-([[:alpha:]]*?)\- } { \c{uns}\cB\{\1\cE\}- } \l_leoboiko_stress_sentence_tl
% do it again
\regex_replace_all:nnN { \-([[:alpha:]]*?)\- } { \c{uns}\cB\{\1\cE\}- } \l_leoboiko_stress_sentence_tl
% remove the surplus -
\regex_replace_all:nnN { \- } { } \l_leoboiko_stress_sentence_tl
% change *<syllable>* into \str{<syllable>}
\regex_replace_all:nnN { \*(.*?)\* } { \c{str}\cB\{\1\cE\} } \l_leoboiko_stress_sentence_tl
% print
\tl_use:N \l_leoboiko_stress_sentence_tl
}

\ExplSyntaxOff

\begin{document}

\uns{A} \uns{po}\uns{ly}\str{syl}\uns{la}\uns{ble} \uns{should} \uns{be} \str{fun} \uns{to} \uns{de}\str{fine}

\stress{A po-ly*syl*la-ble should be *fun* to de*fine*}

\end{document}


• there's a regex replace⁇ that's cheating! kidding, this is wonderful. thank you! – melissa_boiko May 16 '17 at 8:15