3

For example,

\newenvironment{genPage}[2]
  {\clearpage\thispagestyle{#1}\normalsize\bfseries
    \if#2=c
        \centering
    \fi
  }
{\newpage}

\begin{document}
    \begin{genPage}{plain}{c}
    Some text...
    \end{genPage}
\end{document}

It is obvious that what I want to do is understood... Thanks in advance

EDIT: I'm sorry, I still have a problem. When I leave empty the arguments of the environment, the macros \pagestyle{empty},\centering,\bfseries also apply

\newenvironment{genPage}[3]{%
    \clearpage
     {%
        \newcommand{\tempmacroe}{\detokenize{e}}%
        \newcommand{\tempmacroE}{\detokenize{#1}}%
        \newcommand{\tempmacrob}{\detokenize{b}}%
        \newcommand{\tempmacroB}{\detokenize{#3}}%
        \newcommand{\tempmacroc}{\detokenize{c}}%
        \newcommand{\tempmacroC}{\detokenize{#2}}%
        \expandafter
    }%

    \ifx\tempmacroe\tempmacroE
        \thispagestyle{empty}
    \fi
    \ifx\tempmacrob\tempmacroB
        \bfseries
    \fi
    \ifx\tempacroc\tempacroC
        \centering
    \fi
}{\newpage}
3

A syntax such as

\genPage{}{}{}

is not what I'd call a good user interface, but it's your document.

\newenvironment{genPage}[3]
 {%
  \clearpage
  \edef\tempmacroe{\detokenize{e}}%
  \edef\tempmacroE{\detokenize{#1}}%
  \edef\tempmacrob{\detokenize{b}}%
  \edef\tempmacroB{\detokenize{#3}}%
  \edef\tempmacroc{\detokenize{c}}%
  \edef\tempmacroC{\detokenize{#2}}%
  \ifx\tempmacroe\tempmacroE
    \thispagestyle{empty}%
  \fi
  \ifx\tempmacrob\tempmacroB
    \bfseries
  \fi
  \ifx\tempacroc\tempacroC
    \centering
  \fi
 }
 {\clearpage}

The group you open before doing the \newcommand parts is wrong, because at the time the tests are performed the values of the \tempmacroX macros are forgotten. The \expandafter you have does nothing at all.

Since an environment forms a group by itself, the values of \tempmacroX will be forgotten as soon as \end{genPage} is executed.

Note that using \newcommand{\tempmacroe}{\detokenize{e}} and similar would work, but \detokenize would not act: in the first test you would compare the replacement texts of \tempmacroe and \tempmacroE which would be

\detokenize{e}

and

\detokenize{#1}

(with #1 replaced with the actual argument), so the test would fail if by chance you end up with an argument e where e has not category code 11.

Using \detokenize (but with \edef) will ensure that the category code of the character used in the argument is irrelevant.

A different test would work as well, provided the argument is always a single token:

\if\detokenize{e}\detokenize{#1}\relax
  \pagestyle{empty}
\fi

This doesn't need defining \tempmacroe and \tempmacroE. If the argument is empty, \if would compare e with \relax.

With pdflatex you can also do

\ifnum\pdfstrcmp{e}{#1}=0
  \pagestyle{empty}%
\fi

which is also independent of category codes and has the advantage of allowing

\newcommand{\thisisane}{e}

\begin{genPage}{\thisisane}{}{}

which will choose \pagestyle{empty}, because the arguments to \pdfstrcmp are expanded.

5

Just remove the = sign, or TeX will try to compare #2 and =:

\documentclass{article}

\newenvironment{genPage}[2]
  {\clearpage\thispagestyle{#1}\normalsize\bfseries
    \if c#2%
        \centering
    \fi
  }
{\newpage}

\begin{document}
\begin{genPage}{plain}{notc}
  Some text...
\end{genPage}
\begin{genPage}{plain}{c}
  Some text...
\end{genPage}
\begin{genPage}{plain}{notcagain}
  Some text...
\end{genPage}
\end{document}

As jfbu noted the environment fails with \begin{genPage}{plain}{cagain}, making the output centered (as it probably shouldn't), and typesetting again Some text.... But it is obvious you know that ;)

Perhaps a safer approach that performs a token comparison with \ifx:

\newenvironment{genPage}[2]
  {\clearpage\thispagestyle{#1}\normalsize\bfseries
   {% group to restore tempmacroa and tempmacrob to whatever they were before
   \def\tempmacroa{c}%
   \def\tempmacrob{#2}%
   \expandafter}%
    \ifx\tempmacroa\tempmacrob
        \centering
    \fi
  }
{\newpage}

or, as Joseph suggested, a string comparison using \detokenize:

\newenvironment{genPage}[2]
  {\clearpage\thispagestyle{#1}\normalsize\bfseries
   {%
   \edef\tempmacroa{\detokenize{c}}%
   \edef\tempmacrob{\detokenize{#2}}%
   \expandafter}%
    \ifx\tempmacroa\tempmacrob
        \centering
    \fi
  }
{\newpage}
  • 1
    perhaps clarify that the \if c#2 will compare c with the first token in #2, so with cagain the test is positive and leaves "again" in the token stream? (ending in typeset output) – user4686 Aug 24 '18 at 13:02
  • 1
    Perhaps clarify that the \ifx test compares tokens? If you want strings, \edef\@tempa{\detokenize{#2}}, etc. – Joseph Wright Aug 24 '18 at 18:05
  • Ideally, \reserved@a, etc., should only be used by the kernel itself – Joseph Wright Aug 24 '18 at 18:06
  • @JosephWright I didn't know that \reserved@a should only be used by the kernel, I thought they were all-purpose temporaries. I didn't know what I expected from a macro which name is \reserved :P Thanks – Phelype Oleinik Aug 24 '18 at 18:08
  • 1
    ok, removing my comments as egreg's answer is now there – user4686 Aug 25 '18 at 12:41
1

With your code \detokenize does never get carried out. What is your intention when using it?

The empty line behind the closing brace yields a \par-token and the \expandafter-token is applied to that.

You could probably do something like

\newenvironment{genPage}[3]{%
  \clearpage
  {%
    \def{\tempmacroe}{e}%
    \def{\tempmacroE}{#1}%
    \def{\tempmacrob}{b}%
    \def{\tempmacroB}{#3}%
    \def{\tempmacroc}{c}%
    \def{\tempmacroC}{#2}%
    \def\tempmacro{}%
    \ifx\tempmacroe\tempmacroE
      \expandafter\def\expandafter\tempmacro\expandafter{\tempmacro\thispagestyle{empty}}%
    \fi
    \ifx\tempmacrob\tempmacroB
      \expandafter\def\expandafter\tempmacro\expandafter{\tempmacro\bfseries}%
    \fi
    \ifx\tempacroc\tempacroC
      \expandafter\def\expandafter\tempmacro\expandafter{\tempmacro\centering}%
    \fi
  \expandafter}\tempmacro
}{\newpage}

As you tried to do with your snippet of code, the most straightforward approach for comparing two arbitrary brace-balanced token sequences is using each of them as ⟨replacement  text⟩ of another scratch-macro and \ifx-comparing the scratch macros:

\documentclass{article}

\makeatletter
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\DeclareRobustCommand\UnexpandableCheckWhetherTokenSequencesAreEqual[2]{%
  \begingroup
  \def\UD@tempa{#1}%
  \def\UD@tempb{#2}%
  \expandafter\endgroup
  \ifx\UD@tempa\UD@tempb 
     \expandafter\UD@firstoftwo
  \else
     \expandafter\UD@secondoftwo
  \fi
}%
\makeatother

\begin{document}

\UnexpandableCheckWhetherTokenSequencesAreEqual{Foo}{Bar}%
{Token sequences are equal.}%
{Token sequences are differing.}


\UnexpandableCheckWhetherTokenSequencesAreEqual{Foo}{Foo}%
{Token sequences are equal}%
{Token sequences are differing}

\end{document}

Pitfalls:

Routines like this one cannot be used in expansion-contexts like \edef or \csname..\endcsname as (re)defining scratch macros implies performing assignments while the tokens representing assignment do not get carried out at the stage of expansion.

After defining \def\macro{A}, A and \macro are taken for different things although expansion yields the same token-sequence.

Explicit character tokens are taken for something that is differing from their implicit pendants.

E.g., the character token A of catcode 11(letter) will be taken for something that is differing from the implicit-character-token \A which is defined via \let\A=A.

Explicit character tokens of one catcode are taken for something that is differing from their explicit pendants of differing catcode.

E.g., an A of catcode 12(other), which might come into being, e.g., due to \string A is taken for something that differs from an A of catcode 11(letter) which might come into being due to reading in the input and tokenizing an A-character.


For expandably comparing sequences of tokens whereof only one is not yet specified at the time of writing the comparison-routine and whereof the specified ones do not contain braces / do not contain explicit character tokens of category code 1 or 2, TeX' \if-primitives are not needed at all.

You can do it by using macros with delimited arguments, using those strings that are already specified as argument delimiters:

\documentclass{article}

\makeatletter
%%----------------------------------------------------------------------
%% Paraphernalia
%%----------------------------------------------------------------------
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
%%----------------------------------------------------------------------
%% Check whether argument is empty:
%%......................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
%%
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
  \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
  \UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%----------------------------------------------------------------------
%% Check whether argument does not contain "!":
%%......................................................................
\newcommand\UD@GobbleToExclam{}%
\long\def\UD@GobbleToExclam#1!{}%
\newcommand\UD@CheckWhetherNoExclam[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@GobbleToExclam#1!}%
}%
%%----------------------------------------------------------------------
%% Implement Forking depending on the argument holding specific strings:
%%......................................................................
%% For showing the gist of the mechanism, let's crank out the cases of
%% the argument being empty, of the argument being "AAA", of the 
%% argument being "BBB", of the argument being "CCC", of the argument
%% being "DDD", of the argument being "EEE", of the argument being
%% something else.
\newcommand\UD@StringFork{}%
\long\def\UD@StringFork#1!!AAA!BBB!CCC!DDD!EEE!#2#3!!!!{ #2}%
%%
\newcommand\StringFork[1]{%
  \romannumeral0%
  \UD@CheckWhetherNoExclam{#1}{%
     \UD@StringFork
       !#1!AAA!BBB!CCC!DDD!EEE!{Tokens in case argument is empty.}%
       !!#1!BBB!CCC!DDD!EEE!{Tokens in case argument is AAA.}%
       !!AAA!#1!CCC!DDD!EEE!{Tokens in case argument is BBB.}%
       !!AAA!BBB!#1!DDD!EEE!{Tokens in case argument is CCC.}%
       !!AAA!BBB!CCC!#1!EEE!{Tokens in case argument is DDD.}%
       !!AAA!BBB!CCC!DDD!#1!{Tokens in case argument is EEE.}%
       !!AAA!BBB!CCC!DDD!EEE!{Tokens in case argument is something else that contains no exclamation mark.}%
       !!!!%
  }{%
     Tokens in case argument is something else that contains an exclamation mark.%
  }%
  % The "Tokens in case..."-thingies can, e.g., be provided as arguments #2..#9 of
  % \StringFork.
  %
  % It is also feasible to let the "Tokens in case..."-thingies be numbers.
  %
  % When doing this, you can place the call to the \StringFork-macro as 
  % <numberK>-argument within the call to a macro
  %  \getKthArgumentOfLArguments{<numberK>}{<numberL>}%
  %     {Argument 1}%
  %     {Argument 2}%
  %     ...
  %     {Argument L}%
  % where L can be larger than 10.
  % 
  % When doing this, you can place the call to the \StringFork-macro as
  % <number>-argument within an \ifcase<number> ..\or ..\or ... \else...\fi-statement.

}%
\makeatother

\parindent=0pt\relax

\begin{document}

\medskip\verb|\StringFork{!AAA!BBB!CCC!DDD!EEE!}|:\\
\StringFork{!AAA!BBB!CCC!DDD!EEE!}

\medskip\verb|\StringFork{AAA}|:\\
\StringFork{A{A}A}

\medskip\verb|\StringFork{FooBar}|:\\
\StringFork{FooBar}

\medskip\verb|\StringFork{ }|:\\
\StringFork{ }

\medskip\verb|\StringFork{}|:\\
\StringFork{}

\medskip\verb|\StringFork{AAA}|:\\
\StringFork{AAA}

\medskip\verb|\StringFork{BBB}|:\\
\StringFork{BBB}

\medskip\verb|\StringFork{CCC}|:\\
\StringFork{CCC}

\medskip\verb|\StringFork{DDD}|:\\
\StringFork{DDD}

\medskip\verb|\StringFork{EEE}|:\\
\StringFork{EEE}

\end{document}

enter image description here

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.