[Tex/LaTex] How to compare against a constant with ifx

macros

I am trying to test one char substrings (TeX or LaTeX):

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}

\usepackage{fp,stringstrings}

\newcommand*{\mytest}[1]{%
  \def\firstChar{\substring{#1}{1}{1}}%
  \ifx M\firstChar\textit{M has been recognized}\else\textbf{M has NOT been recognized, firstChar='\firstChar'}\fi
}

\begin{document}\thispagestyle{empty}
Test with Matching: \mytest{Matching}\par
Test with M:  \mytest{M}\par
Test with No: \mytest{No}\par
Test with N:  \mytest{N}\par
\end{document}

Expected result is "M has been recognized" for the first two calls.
What I obtain is:enter image description here

How to compare against a constant with ifx ?

Best Answer

\ifx compares the meaning of the two following tokens without expanding them. So you're testing whether the token M has the same meaning as \firstChar and they don't, even if \def\firstChar{M} has been issued, because M is a character and \firstChar is a macro.

You have to expand \firstChar:

\expandafter\ifx\expandafter M\firstChar

But this wouldn't work with that string extraction, because \firstChar expands to instruction for extracting the first character, not to the first character. A better (and simpler) test is

\makeatletter
\def\extract@first#1#2\@nil{#1}
\newcommand*{\mytest}[1]{%
  \expandafter\ifx\expandafter M\extract@first#1\@empty\@nil
    \textit{M has been recognized}%
  \else
    \textbf{M has NOT been recognized, firstChar=`\extract@first#1\@empty\@nil'}%
  \fi
}
\makeatother

This works also with an empty string. However, this will not work with multibyte UTF-8 characters, unless a UTF-8 savvy engine (XeLaTeX or LuaLaTeX) is used. Working with UTF-8 is much more difficult.

Complete example:

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}

\makeatletter
\def\extract@first#1#2\@nil{#1}
\newcommand*{\mytest}[1]{%
  \expandafter\ifx\expandafter M\extract@first#1\@empty\@nil
    \textit{M has been recognized}%
  \else
    \textbf{M has NOT been recognized, firstChar=`\extract@first#1\@empty\@nil'}%
  \fi
}
\makeatother

\begin{document}\thispagestyle{empty}
Test with Matching: \mytest{Matching}\par
Test with M:  \mytest{M}\par
Test with No: \mytest{No}\par
Test with N:  \mytest{N}\par
Test with empty: \mytest{}\par
\end{document}

enter image description here

Related Question