1

Assume there is defined a macro \foo:
\def\foo{\bar\space A hash {in {braces: \string##}\string##}}

Expanding a control word token/macro token \foo yields:
\bar\spaceA1110h11a11s11h1110{1i11n1110{1b11r11a11c11e11s11:1210\string#6}2\string#6}2

Assume none of the control sequence tokens ocurring within this is \outer.

How to post-process to have each hash/each explicit character token of category 6/parameter doubled in order to get
\bar\spaceA1110h11a11s11h1110{1i11n1110{1b11r11a11c11e11s11:1210\string#6#6}2\string#6#6}2 ?

That in turn can be used as (a component of) the ⟨replacement text⟩ of another macro that is to be defined via \def and where I don't like to change to defining via \edef\AnotherMacro{\unexpanded{..}}/where I don't like to change to \edef\AnotherMacro{\the\tokenregister} as the code that carries out the \def and that would need to be changed comes from a macro package which is not mine and where I don't know if users rely on things not being changed/not being patched.

(Unfortunately, within replacement texts of many macros of pgfkeys, where a thing like \edef\macro{\unexpanded{#1}} could be used to allow hashes as components of the argument denoted by the parameter #1, \def\macro{#1} is used. This seems to be the case, e.g., with routines underlying handlers like .store in and .search also. In case this is already rectified in most recent pgfkeys: One of my colleagues still uses TeX Live 2018 and won't update until retiring.)

I know that \meaning, \write and \scantokens and \detokenize double hashes, but with these you loose information about categories of character tokens. And in case of flipping category codes of characters between 11 and s.th. else, you also don't know what characters belong to the names of what control sequences. And in case \escapechar is changed or not positive, you don't even know what characters belong to the names of control sequences at all.

2
  • 1
    I don't think this is possible in full generality Feb 12 at 22:08
  • See the answers to How to have hashes doubled and things expanded?. E.g., my method \DoubleEveryHash is not bound to things being expanded. But as a side effect it replaces any explicit character tokens of category 1/2 by curly braces of category 1/2. This might be a problem with macros defined using #{-notation, { being an explicit character token of category 1 other than curly left brace. Double hashes inside macro definition? might be of interest, too. Feb 12 at 23:00

2 Answers 2

1

There are functions in etl that can search&replace macro parameter tokens. It has a few other shortcomings though (see its documentation, mostly it's about a few internal tokens not being allowed, the fact that it normalises category 1 and 2 tokens to {}, and the fact that some tokens can't be distinguished expandably from each other).

Be that as it may, the following implements a hash doubling with a straight forward single call to a function, and then uses it in some pseudo-setup macro as an example for your pgfkeys-internal. I removed the \bar so that I can typeset the contents without further changes.

\documentclass{article}

\usepackage{etl}

\def\foo{\space A hash {in {braces: \string##}\string##}}

\ExplSyntaxOn
\cs_new:Npn \cattleya_double_hashes:n #1
  { \etl_token_replace_all_deep:nNn {#1} ## { #### } }
\cs_new_eq:NN \doublehashes \cattleya_double_hashes:n
\ExplSyntaxOff

% the other definition you don't have control over
\NewDocumentCommand\mysetupmacro{m}
  {\def\macro{Stuff and #1 and stuff}}
\newcommand*\macro{} % initial value

\expanded{\noexpand\mysetupmacro{\expandafter\doublehashes\expandafter{\foo}}}

\begin{document}
\texttt{\meaning\macro}

\macro
\end{document}

enter image description here

0

I am not sure if this token cycle meets your requirements:

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{tokcycle,lmodern}
\tokcycleenvironment\showcats
 {\ifcatSIX\addcytoks{\thistok{##1}{6}}\else\addcytoks{\catcomp{##1}}\fi}
 {\addcytoks{\thistok{\{}{1}}\processtoks{##1}\addcytoks{\thistok{\}}{2}}}
 {\addcytoks{\catcomp{##1}}\tctestifx{\par##1}{\addcytoks{\par}}{}}
 {\ifimplicittok\addcytoks{\catcomp{##1}}\else
  \addcytoks{\thistok{\textvisiblespace}{\number\catcode`##1}}\fi}
\newcommand\thistok[2]{#1$_{#2}$\,\allowbreak}
\makeatletter
\newcommand\catcomp[1]{%
  \tctestifx{\implicitsixtok#1}{\expandafter\string#1$_{6}}{%
  \string#1$_{%
  \tctestifcatnx #1\relax{0}{%
  \tctestifcatnx #1${3}{%
  \tctestifcatnx #1&{4}{%
  \tctestifcatnx #1^{7}{%
  \tctestifcatnx #1_{8}{%
  \tctestifcatnx #1\@sptoken{10}{%
  \tctestifcatnx #1a{11}{%
  \tctestifcatnx #11{12}{%
  \tctestifcatnx #1~{13}{%
  *%
  }}}}}}}}}}%
  }$\,\allowbreak%
}
\makeatother
\begin{document}

\let\foo\relax

\showcats\def\foo{\bar\space A hash {in {braces: \string##}\string##}}\endshowcats

\hrulefill

\def\foo{\bar\space A hash {in {braces: \string##}\string##}}

\detokenize\expandafter{\foo}

\expandafter\showcats\foo\endshowcats

\hrulefill

\newcommand\addhash{\cytoks\expandafter{\the\cytoks####}}

\resettokcycle
\Characterdirective{\ifcatSIX\addhash\addhash\else\addcytoks{#1}\fi}
\expandafter\tokcyclexpress\expandafter{\foo}
\expandafter\def\expandafter\food\expandafter{\the\cytoks}

\detokenize\expandafter{\food}

\expandafter\showcats\food\endshowcats
\end{document}

enter image description here

In the first block of output, the double hashes can be recognized, if processed before the \def takes place, but this is not what you need.

In the 2nd block, if the \def occurs first, the double hash is lost, per the rules of \def.

In the 3rd block, the double hash is restored, by operating the given token cycle upon the predefined \foo to create \food with a \def of the cycle tokens. I show the detokenization \food, as well as its token/catcode breakdown.

This might be what you requested, I hope.

You must log in to answer this question.