3

What I want to do is replace {...} (token group) by \{...\} (curly braces) at any level of nesting inside an expression. I'm only able to do it for level = 0. There should be an extra curly brace around the second 'o' in the example given. Any suggestion?

\documentclass{article}
\ExplSyntaxOn

\cs_new:Nn
\__erw_unbrace_scan:n
{ %\group_begin:
  \__erw_scan:n#1
  %\group_end:
}

\cs_new:Nn
\__erw_aux:n
{  \tl_if_single_token:nTF{#1}{#1}
  { \{\__erw_unbrace_scan:n{#1}\}}}

\cs_new:Npn
\__erw_scan:w #1 #2 #3 \q_recursion_stop
{\quark_if_recursion_tail_stop:n{#2}
  \__erw_aux:n{#1}
  \__erw_scan:w {#2} #3 \q_recursion_stop}

\cs_new:Nn
\__erw_scan:n
{\__erw_scan:w #1 {dummy}\q_recursion_tail\q_recursion_stop}

\ExplSyntaxOff
\begin{document}
\ExplSyntaxOn

\tl_if_single_token:nTF{x}{T}{F}\par
\tl_if_single_token:nTF{{x}}{T}{F}\par

\__erw_scan:n{f{o{o}}bar} % expected: f\{o\{o\}\}bar

\ExplSyntaxOff
\end{document}

enter image description here

1

Without Expl3, here is a token cycle approach.

While brace conversion could easily mess with macro arguments, the MWE shows that for macros that do not rely on braced arguments, they can be part of the converted stream.

\documentclass{article}
\usepackage{tokcycle}
\stripgroupingtrue
\Groupdirective{\addcytoks{\{}\processtoks{#1}\addcytoks{\}}}
\newcommand\groupscan[1]{\tokcyclexpress{#1}\the\cytoks}
\begin{document}
\groupscan{f{o{o}}bar}

\groupscan{f{o{{\today}}}bar}
\end{document}

enter image description here

5

If a TeX solution is allowed (this is fully expandable)

\makeatletter
\def\erw#1{\erwAuxi#1\@gobbletwo{}}
\def\erwAuxi#1#{#1\erwAuxii}
\def\erwAuxii#1{\{\erw{#1}\}\erwAuxi}
\makeatother

\erw{f{oo}bar{baz}{} {a{bc{def}}}}

output

uses the #{ trick.

1
3

This is not fully expandable, but does the job and the same code can be adjusted for other balanced tokens.

\documentclass{article}

\ExplSyntaxOn

\NewDocumentCommand{\showbraces}{m}
 {
  \erwann_showbraces:n { #1 }
 }

\tl_new:N \l__erwann_showbraces_tl

\cs_new_protected:Nn \erwann_showbraces:n
 {
  \tl_set:Nn \l__erwann_showbraces_tl { #1 }
  % start the recursion
  \__erwann_showbraces:
 }

\cs_new_protected:Nn \__erwann_showbraces:
 {
  \regex_match:nVTF { \{.*\} } \l__erwann_showbraces_tl
   {% there is a match, modify
    \regex_replace_all:nnN { \{(.*?)\} } { \c{\{}\1\c{\}} } \l__erwann_showbraces_tl
    % reapply
    \__erwann_showbraces:
   }
   {% no match, deliver the result
    \tl_use:N \l__erwann_showbraces_tl
   }
 }
\prg_generate_conditional_variant:Nnn \regex_match:nn { nV } { T, F, TF }

\ExplSyntaxOff

\begin{document}

\showbraces{f {oo}bar{baz}{} {a{bc{def}}}}

\end{document}

enter image description here

1
  • The reason I got started toying with recursion is because regex is not expandable as you reminded, but for the narrow task at hand your answer suffices. Do you know why my solution does not work?
    – Erwann
    Sep 5 at 11:57
1

If braces are stripped out in the normal course of processing, then letting them be stripped out and inserting text braces just beforehand would keep everything balanced and not require recursion, wouldn't it?

braces

MWE

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

%=====
\tl_new:N \l_mytemp_tl
%=====
\NewDocumentCommand { \scanbraces } { m } {

    \tl_set:Nn \l_mytemp_tl { #1 } % no expansion
    %\tl_show:N \l_mytemp_tl 
    
    \regex_replace_all:nnN 
                { (\c{[A-Za-z]*}) } %any control sequence with Latin letters
                { \c{token_to_str:N} \1  } %convert to string
                \l_mytemp_tl    
    
    \regex_replace_all:nnN 
                { (\cB.) } %match on opening group
                { \1\c{\{}  } %insert a text brace
                \l_mytemp_tl
    
    \regex_replace_all:nnN 
            { (\cE.) } %match on closing group
            { \1\c{\}}  } %insert a text brace
             \l_mytemp_tl

    \tl_use:N \l_mytemp_tl
    
}

\ExplSyntaxOff


\newcommand\ftest[1]{\textit{#1}}
\newcommand\qq[2][]{\begin{quotation}#1#2\end{quotation}}
\begin{document}
For a command defined as \verb|\newcommand\ftest[1]{\textit{#1}}|

then keying in

\qq[\ttfamily]{\scanbraces{\ftest{o{o}}bar} }

typesets

\qq{\ftest{o{o}}bar}

\end{document}

@egreg

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.