3

I am trying to capture punctuation marks and I have a number of macros, two of which are shown in the minimal below:

\documentclass{article}
\usepackage[english]{babel}
\def\isColon#1{%
\ifx:#1
    colon!
\else
   Not a colon!
\fi}

\def\isPeriod#1{%
\ifx.#1
   Period!
\else
   Not a period!
\fi}

\begin{document}
\isColon:

\isPeriod.
\end{document}

If the babel language is changed to [french,english] the colon is not captured, as babel makes it active. What modifications are required to the isColon macro to work in both cases?

6

I'd use \if:

\documentclass{article}
\usepackage[english]{babel}
\def\isColon#1{%
\if:\noexpand#1%
    colon!
\else
   Not a colon!
\fi}

\def\isPeriod#1{%
\if.\noexpand#1%
   Period!
\else
   Not a period!
\fi}

\begin{document}
\isColon:

\isPeriod.
\end{document}

Another alternative would be \pdfstrcmp, but that is probably overkill here.

  • Note: The TeX \if test is used much less often than \ifx, but as it compares two character codes it is idea here. The \pdfstrcmp primitive, available in pdfTeX, XeTeX (as \strcmp) and in LuaTeX (using a small piece of Lua) does a general character-based comparison, and is therefore useful in cases where you have two strings and want to ignore category codes. – Joseph Wright Dec 26 '10 at 19:07
4
\documentclass{article}
\usepackage[english,french]{babel}
\shorthandon{:}
\def\isColon#1{%
  \ifx:#1
    colon!
  \else
     Not a colon!
  \fi}%

\def\isPeriod#1{%
\ifx.#1
   Period!
\else
   Not a period!
\fi}

\begin{document}
\isColon: \isColon;

\isPeriod.
\end{document}
  • 1
    This solution is not expandable: while this was not requested in the question, I think it's often useful to do it if possible. – Joseph Wright Dec 26 '10 at 9:41
  • 1
    @Joseph: true, I changed the code – user2478 Dec 26 '10 at 10:15
2

The problem is that outside of the macro, : is a macro expanding to \active@prefix :\normal@char: , but inside the macro, : is just the character :. I believe this is because Babel registers the catcode changes with \AtBeginDocument; moving the macro definition after \begin{document} works just fine. I also found that simply changing \ifx to \if worked fine without moving the macro definition. But I think the cleanest solution (though a slightly specific one) is probably to change :'s catcode to active for the definition of \isColon:

\catcode`\:=\active
\def\isColon#1{%
\ifx:#1
    colon!
\else
   Not a colon!
\fi}
\catcode`\:=12

Edit: In case : has its catcode changed by something else, you ought to use this version instead:

\begingroup
  \catcode`\:=\active
  \gdef\isColon#1{%
    \ifx:#1
      colon!%
    \else
      Not a colon!%
    \fi}
\endgroup

This resets the catcode of : to whatever it was before, not simply to 12.

  • 1
    @Antal: you are taking an incompatibility risk here when reverting : to catcode 12: maybe its catcode was changed by some other package. For these cases, I believe that it is better to put \begingroup before the catcode change, and \endgroup instead of reverting the catcode. Then we also need to change \def by \gdef. – Bruno Le Floch Jan 14 '11 at 12:50
  • 1
    @Bruno,@Antal: you can also do the same without a catcode change and without a \gdef thanks to a lccode trick: \begingroup\lccode`\~=`\:\lowercase{\endgroup\def\isColon#1{\ifx~#1 colon!\else Not a colon!\fi}} – Philippe Goutet Jan 14 '11 at 22:25
  • 2
    @Antal: with the \lccode change, \lowercase replaces ~ with : but doesn't change the catcode, so you obtain a : with catcode 13. More details in tex.stackexchange.com/questions/7359 – Philippe Goutet Jan 15 '11 at 9:43
  • 1
    @Philippe: "Not a colon!" will also be lowercased, though, so we need to add \lccode\N=\N before \lowercase. – Bruno Le Floch Jan 15 '11 at 12:48
  • 1
    @Bruno: yes, or you could put "Not a colon!" and "colon!" each inside a macro to avoid any hassle of this kind. – Philippe Goutet Jan 15 '11 at 14:05

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.