# Changing catcode for commercial at (@) inside a macro to get it matched in pattern.

This question is related to TikZ: pgfutil-common: pgfutil@in@ - how does it work? and is a result of coping with that problem. I've already read How to change #catcode in a macro, but it didn't help me.

So, here is minimalistic example of what I have. Play with \makeatletter ... \makeatother inside document environment.

\documentclass{article}

\usepackage{tikz}

% Consider start of library here (this part is located in a separate file included by means of \usetikzlibrary).
\makeatletter

\def \myparse #1{%
\def \myparse@ ##1 @ ##2\pgf@stop{%
\def \beforeat{##1}%
\def \afterat{##2}%
}
%
\def \tikz@temp{#1}%
%
\def \beforeat{false before}%
\def \afterat{false after}
\edef \pgf@marshal{\noexpand \pgfutil@in@{@}{\tikz@temp}}%
\pgf@marshal \ifpgfutil@in@%
\expandafter \myparse@ \tikz@temp\pgf@stop%
\fi%
}

\makeatother
% Consider end of library here.

% User's file starts here.

\begin{document}
\makeatletter % Play with commenting out this line.
\myparse{true before @ true after}
\makeatother % and this one.

\beforeat\par
\afterat\par
\end{document}


I'd like to eliminate the need in \makeatletter ... \makeatother in user's file, while remaining usage of @ symbol.

-

You might also want to read What do \makeatletter and \makeatother do?. Broadly, in order to use a macro such as \pgfutil@in@, @ has to be a 'letter' as far as TeX is concerned. This is because TeX works out what is a control sequence (macro name) based on what 'letters' are. If you try to use a macro such as \pgfutil@in@ without \makeatletter then TeX will look for a macro called \pgfutil, which may or may not lead to an error but certainly will not be what you want.

The code you've posted includes an @ which will need to be an 'other' character, not a letter. The standard way to include a character with an 'awkward' category code is to use \lowercase, for example

\makeatletter
\begingroup
\lccode\*=\@\relax
\lowercase{%
\endgroup
\def\test#1*{stuff}%
}%
\makeatother
\test 123@456


This works because TeX does not change the category code of the token when it changes the character code (broadly, when it makes it lower case). This will seem strange to people familiar with many other programming languages, but is a standard approach for TeX programmers.

-
Finally, I got it working with your help! Thank you the very much! –  Dmitrii F. Volosnykh May 4 '11 at 18:47
You could change it to \lowercase{\endgroup\def\test#1*}{stuff}% then stuff is not changed by \lowercase so you can also have uppercase content. –  Martin Scharrer May 4 '11 at 19:13
@Martinn: True, but even more confusing for the non-expert! –  Joseph Wright May 4 '11 at 19:16
@Martin: Could you also explain, why do we need \begingroup, \endgroup here? I tried to remove them, and it still works fine. –  Dmitrii F. Volosnykh May 4 '11 at 19:56
@Dmitry: The group is used so that the change of \lccode is localised. Normally, the lower case equivalent of * is 'no change', which is what most people would expect. Try doing \lowercase{*} after the code with and without the group and see the difference. –  Joseph Wright May 4 '11 at 20:00

The following appears to work (edited from five minutes ago, sorry but I thinnk I finally got it right even if it looks simplistic in the end):

\documentclass{article}

\usepackage{tikz}

% Consider start of library here (this part is located in a separate file included by means of \usetikzlibrary).
\makeatletter

\def \myparse #1{%
\def \myparse@ ##1 @ ##2\pgf@stop{%
\def \beforeat{##1}%
\def \afterat{##2}%
}
%
\def \tikz@temp{#1}%
%
\def \beforeat{false before}%
\def \afterat{false after}
\edef \pgf@marshal{\noexpand \pgfutil@in@{@}{\tikz@temp}}%
\pgf@marshal \ifpgfutil@in@%
\expandafter \myparse@ \tikz@temp\pgf@stop%
\fi
}

\makeatother
% Consider end of library here.

\def\MyParsei #1{\myparse{#1}\makeatother}
\def\MyParse{\makeatletter\MyParsei}

% User's file starts here.

\begin{document}
\myparse{true before @ true after}
\beforeat\par
\afterat\par

\MyParse{true before @ true after}
\beforeat\par
\afterat\par

\myparse{true before @ true after}
\beforeat\par
\afterat\par

\end{document}

-
@everybody: I understand that this is not usable in the argument to a macro due to the freezing of catcodes (putting it in an \hbox for example reveals the problem), but I just wanted the simple idea of my initial post (which I deleted after having modified it for something worse) brought to conclusion. cheers –  jfbu May 5 '11 at 7:31