On Sun, Apr 26, 2009 at 08:27:38AM +0200, Uwe Lück wrote: > The difference in safety is that other proposals can be fooled by \in@ or > \in@@ in \in@ arguments. The "safe" proposal still can be fooled by \@nil > or so in \in@ arguments. This can be fixed without a new command token: > Right, on the other hand \in@{a}{a#} and \in@{b}{a#} work with the > expandable tests only. This can be fixed using token registers, see below. `#' cannot be used in the first substring argument, because it cannot be used as ordinary delimiter in the parameter text of a definition (except as last token, but this doesn't help here). Then `#' should be a better token than \@nil or \[log in to unmask] ==> \in@@#2###1\in@\in@@ > 1. LaTeX-so-far, We are currently discussing the bugs of this version. > 2.changing it by just inserting a separator in the last > line according to Morten: > > \def\in@#1#2{% > \def\in@@##1#1##2##3\in@@{% > \ifx\in@##2\in@false\else\in@true\fi}% > \in@@#2\@nil#1\in@\in@@} It can be broken like the original macro by \in@{}{} Then the call of \in@@ is one argument too short. This can be fixed by preceding the string by a token. ==> \in@@###2###1\in@\in@@ > (where I proposed to use \@in@ in place of \@nil), and (or `#', see above.) > 3. mine (expandable > test without \in@). (Attached is a file with testing tools for the four > versions.) The expandable tests can be broken by conditionals, e.g.: \in@{a}{a{\fi\fi}} > In favour of Morten's: it is the least change (compatibility). Then I would prefer the following modification: % Version M: \def\in@#1#2{% \def\in@@##1#1##2##3\in@@{% \ifx\in@##2\relax % \relax added for the case that ##2 is empty \in@false \else \in@true \fi }% \in@@###2###1\in@\in@@ } I think, a little more robust is, but longer is: % Version H: \def\in@#1#2{% \def\in@@{#1}% \ifx\in@@\@empty \in@true \expandafter\@gobble \else \expandafter\@firstofone \fi {% \def\in@@##1#1##2\in@@{% \begingroup \toks@{##2}% \edef\in@@{\the\toks@}% \expandafter\endgroup \ifx\in@@\@empty \in@false \else \in@true \fi }% \in@@#2###1\in@@ }% } There are some cases to discuss, if the first argument is empty. The kernel version behaves the following way: \in@{}{} breaks and \in@{}{a} -> false \in@{}{ab} -> true is inconsistent. I would like a more standardized behaviour (e.g. Perl's `index' function for substring searching): If the first argument is empty, then the result is always true: \in@{}{} -> true \in@{}{a} -> true \in@{}{ab} -> true Both versions M and H behave in this way. Test file: \catcode`\@=11 % \def\@empty{}% (for testing with plain-TeX) \long\def\@gobble#1{} \long\def\@firstofone#1{#1} \def\kernel@in@#1#2{% \def\in@@##1#1##2##3\in@@{% \ifx\in@##2% \in@false \else \in@true \fi }% \in@@#2#1\in@\in@@ } %%% Variant M begin %%% \def\M@in@#1#2{% \def\in@@##1#1##2##3\in@@{% \ifx\in@##2\relax \in@false \else \in@true \fi }% \in@@###2###1\in@\in@@ } %%% Variant M end %%% %%% Variant H begin %%% \def\H@in@#1#2{% \def\in@@{#1}% \ifx\in@@\@empty \in@true \expandafter\@gobble \else \expandafter\@firstofone \fi {% \def\in@@##1#1##2\in@@{% \begingroup \toks@{##2}% \edef\in@@{\the\toks@}% \expandafter\endgroup \ifx\in@@\@empty \in@false \else \in@true \fi }% \in@@#2###1\in@@ }% } %%% Variant H end %%% \expandafter\ifx\csname ifin@\endcsname\relax \expandafter\newif\csname ifin@\endcsname \fi \def\msg#{\immediate\write16} \def\@test#1#2#3#4{% #4{#1}{#2}% \edef\@result{% \ifin@ yes\else no\fi }% \def\@expected{#3}% \toks@={{#1}{#2}}% \msg{% [\string#4\the\toks@\space = \@result\space] => % \ifx\@result\@expected OK.\else FAILED!\fi }% } \def\test#1#2#3{% \@test{#1}{#2}{#3}\in@ } \msg{} \msg{* Inconsistent behaviour of the kernel} \@test{}{a}{yes}\kernel@in@ \@test{}{ab}{yes}\kernel@in@ \@test{a}{}{no}\kernel@in@ \@test{\iftrue}{\iftrue}{yes}\kernel@in@ \@test{\iffalse}{\iffalse}{yes}\kernel@in@ \@test{\iftrue}{\iffalse}{no}\kernel@in@ % \let\M@in@ \let\in@\H@in@ \msg{} \msg{* Tests for fixed version of \string\in@} \test{}{a}{yes} \test{}{}{yes} \test{a}{}{no} \test{a}{{}}{no} \test{a}{a{}}{yes} \test{a}{{}a}{yes} \test{a}{b{}}{no} \test{a}{{}b}{no} \test{bon}{#bon}{yes} \expandafter\test\expandafter{\string#bon}{#bon}{no} \test{bon\@in}{bon}{no} \test{bon\@in}{bon\@in}{yes} \test{\@in}{\@in}{yes} \test{\@in bon}{\@in\@in bon}{yes} \test{\iftrue}{\iftrue}{yes} \test{\iftrue}{\iffalse}{no} \test{\iffalse}{\iftrue}{no} \test{\iffalse}{\iffalse}{yes} \test{\else}{\else}{yes} \test{\else}{\fi}{no} \test{\fi}{\else}{no} \test{\fi}{\fi}{yes} \test{a}{a{\fi\fi}}{yes} \test{bonbon}{bon}{no} \test{bon}{bonbon}{yes} \test{bona}{bon}{no} \test{bon}{bona}{yes} \test{ionization}{ionizat}{no} \test{client-to-client}{client-to-}{no} \csname @@end\endcsname\end Yours sincerely Heiko <[log in to unmask]>