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

Erwann
  • 2,100

4 Answers4

6

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.

plante
  • 1,349
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

egreg
  • 1,121,712
  • 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 05 '21 at 11:57
2

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

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

Cicada
  • 10,129