6

Please consider the following code:

\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:

enter image description here (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?

4

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}

enter image description here

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.