Trying to get \zap@space and \lowercase to work on string comparison

An expl3 solution. Here, I use the fact that \tl_map_function:nN will 'eat' spaces, and do proper case folding rather than lower casing (see the Unicode docs for the reasons that this is important):

\documentclass{article}
\usepackage{expl3,xparse}
\ExplSyntaxOn
\NewExpandableDocumentCommand \compareStrings { m m +m +m }
  {
    \str_if_eq:eeTF % \str_if_eq_x:nnTF in older code
      { \tl_map_function:fN { \str_foldcase:n {#1} } \use:n }
      { \tl_map_function:fN { \str_foldcase:n {#2} } \use:n }
      {#3} {#4}
  }
\cs_generate_variant:Nn \tl_map_function:nN { f }
\ExplSyntaxOff


\begin{document}
\compareStrings{test}{tesT}{1}{2}
\end{document}

You need to apply lowercase to the strings before you compare, so it needs to be outside any \edef here I have used \pdfstrcmp to avoid having to define additional temp macros, this primitive is also available in other engines than pdftex, as \strcmp.

This finds all but the last as equal

enter image description here

\documentclass{article}


%%% Support command %%%
\makeatletter
\newcommand\compareStrings[2]{%
\edef\tempA{\lowercase{\noexpand\ifnum0=\noexpand\pdfstrcmp
    {\noexpand\zap@space#1 \noexpand\@empty}%
    {\noexpand\zap@space#2 \noexpand\@empty}%
}\relax}%
\tempA
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi}

\makeatother
%%%%% End support commands %%%%


\begin{document}

\def\zz{T e sT}
0: \compareStrings{tesT}{tesT}{1}{2}

1: \compareStrings{test}{tesT}{1}{2}

2: \compareStrings{\zz}{tesT}{1}{2}

3: \compareStrings{testj}{tesT}{1}{2}

\end{document}

Be aware that \lowercase neither is expandable nor does trigger expansion of its argument.

Thus you need to ensure that those tokens that expand to characters whose cases are to be changed are already fully expanded when \lowercase or \uppercase comes to action. (Same for \uppercase.)

Be aware that \zap@space does not trigger expansion of its argument.

Thus you need to ensure that those tokens that expand to characters where spaces shall be removed are already fully expanded when \zap@space comes to action.

\documentclass{article}
\usepackage{ifthenx}

\makeatletter
\DeclareRobustCommand\compareStrings[2]{%
  % Make sure each instance of \zap@space gets its argument 
  % expanded - do this by edef-fing while via \noexpand preventing 
  % expansion both of \zap@space and of \@empty. The latter is a
  % sentinel-token for \zap@space and therefore must be let in place
  % untouched also:
  \protected@edef\tempA{%
    {\noexpand\zap@space#1 \noexpand\@empty}%
    {\noexpand\zap@space#2 \noexpand\@empty}%
  }%
  % Now that the arguments for the \zap@space-instances are expanded,
  % via another \protected@edef have carried out the \zap@space-instances:
  \protected@edef\tempA{%
    % \lowercase is not expandable, thus does not get expanded
    % /does not get carried out at "e-def-fing-time". 
    % Expansion of anything else but \tempA is prevented via 
    % \noexpand. Within \tempA anything but the \zap@space-
    % instances is already expanded due to the previous \protected@edef.
    % Thus the only effect of this \protected@edef is carrying
    % out \zap@space-instances on arguments that were expanded by 
    % the previous \protected@edef.
    \lowercase{\noexpand\ifthenelse{\noexpand\equal\tempA}}%
  }%
  % Now in \tempA the arguments are expanded and space tokens
  % are removed. Thus \tempA expands to a call to \lowercase
  % where the arguments are expanded and thus you don't have
  % control-sequence-tokens any more (whereon \lowercase would have
  % no effect) but character-tokens (whereon \lowwercase does have
  % an effect).
  \tempA{\@firstoftwo}{\@secondoftwo}%
}
\makeatother

\parindent=0ex
\parskip=\baselineskip

\begin{document}

\verb|\compareStrings{test}{tesT}{equal}{different}| yields:
\compareStrings{test}{tesT}{equal}{different}

\verb|\compareStrings{test}{t e sT}{equal}{different}| yields:
\compareStrings{test}{t e sT}{equal}{different}

\verb|\compareStrings{test}{t E   sT}{equal}{different}| yields:
\compareStrings{test}{t e sT}{equal}{different}

\verb|\compareStrings{test}{tset}{equal}{different}| yields:
\compareStrings{test}{tset}{equal}{different}

\def\test{test}%
\def\tset{TsEt}%
\verb|\def\test{test}|\\    
\verb|\def\tset{TsEt}|

\verb|\compareStrings{\test}{te s T}{equal}{different}| yields:
\compareStrings{\test}{te s T}{equal}{different}

\verb|\compareStrings{\test}{tSeT}{equal}{different}| yields:
\compareStrings{\test}{tSeT}{equal}{different}

\verb|\compareStrings{\tset}{te s T}{equal}{different}| yields:
\compareStrings{\tset}{te s T}{equal}{different}

\verb|\compareStrings{\tset}{tSeT}{equal}{different}| yields:
\compareStrings{\tset}{tSeT}{equal}{different}

\verb|\compareStrings{\tset}{\test}{equal}{different}| yields:
\compareStrings{\tset}{\test}{equal}{different}

\verb|\compareStrings{\test}{\tset}{equal}{different}| yields:
\compareStrings{\test}{\tset}{equal}{different}

Be aware that \verb|\uppercase| and \verb|\lowercase| are not expandable, thus:

\verb|\compareStrings{\uppercase{test}}{TEST}{equal}{different}| yields:
\compareStrings{\uppercase{test}}{TEST}{equal}{different}

\verb|\compareStrings{\uppercase{test}}{test}{equal}{different}| yields:
\compareStrings{\uppercase{test}}{test}{equal}{different}

\verb|\compareStrings{\lowercase{TEST}}{test}{equal}{different}| yields:
\compareStrings{\lowercase{TEST}}{test}{equal}{different}

\verb|\compareStrings{\lowercase{test}}{test}{equal}{different}| yields:
\compareStrings{\lowercase{test}}{test}{equal}{different}

\end{document}

enter image description here


In case the removal of space tokens needs to be applied in situations where the argument itself may contain braces, I can offer an expandable routine \UD@removeallspace for recursively removing all explicit space tokens from a token sequence even when the argument contains braces, without the need of sentinel-tokens that may not occur within the argument.

As a side-effect the routine does replace pairs of matching explicit character tokens of category code 1/2 by matching braces.

Usually braces are the only characters with catcode 1/2, thus usually this should not be a problem. Usually.

(In case somebody knows a method that can be used in expansion-contexts on old 8bit-engines without e-TeX- or odfTeX-extensions also, and where matching explicit character tokens of category 1/2 will be left in place untouched, I'll be glad to learn abut it. ;-) )

\documentclass{article}
\usepackage{ifthenx}

\makeatletter
%% Code for expandable recursive space-remove-routine:
%%
%%=============================================================================
%% Paraphernalia:
%%    \UD@firstoftwo, \UD@secondoftwo,
%%    \UD@PassFirstToSecond, \UD@Exchange, \UD@removespace
%%    \UD@CheckWhetherNull, \UD@CheckWhetherBrace,
%%    \UD@CheckWhetherLeadingSpace, \UD@ExtractFirstArg
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\newcommand\UD@Exchange[2]{#2#1}%
\newcommand\UD@removespace{}\UD@firstoftwo{\def\UD@removespace}{} {}%
%%-----------------------------------------------------------------------------
%% 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's first token is a catcode-1-character
%%.............................................................................
%% \UD@CheckWhetherBrace{<Argument which is to be checked>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked has leading
%%                        catcode-1-token>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked has no leading
%%                        catcode-1-token>}%
\newcommand\UD@CheckWhetherBrace[1]{%
  \romannumeral0\expandafter\UD@secondoftwo\expandafter{\expandafter{%
  \string#1.}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
  \UD@firstoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether brace-balanced argument starts with a space-token
%%.............................................................................
%% \UD@CheckWhetherLeadingSpace{<Argument which is to be checked>}%
%%                             {<Tokens to be delivered in case <argument
%%                               which is to be checked>'s 1st token is a
%%                               space-token>}%
%%                             {<Tokens to be delivered in case <argument
%%                               which is to be checked>'s 1st token is not
%%                               a space-token>}%
\newcommand\UD@CheckWhetherLeadingSpace[1]{%
  \romannumeral0\UD@CheckWhetherNull{#1}%
  {\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
  {\expandafter\UD@secondoftwo\string{\UD@CheckWhetherLeadingSpaceB.#1 }{}}%
}%
\newcommand\UD@CheckWhetherLeadingSpaceB{}%
\long\def\UD@CheckWhetherLeadingSpaceB#1 {%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@secondoftwo#1{}}%
  {\UD@Exchange{\UD@firstoftwo}}{\UD@Exchange{\UD@secondoftwo}}%
  {\UD@Exchange{ }{\expandafter\expandafter\expandafter\expandafter
   \expandafter\expandafter\expandafter}\expandafter\expandafter
   \expandafter}\expandafter\UD@secondoftwo\expandafter{\string}%
}%
%%-----------------------------------------------------------------------------
%% Extract first inner undelimited argument:
%%
%%   \UD@ExtractFirstArg{ABCDE} yields {A}
%%
%%   \UD@ExtractFirstArg{{AB}CDE} yields {AB}
%%
%% Be aware that (La)TeX does discard preceding space tokens when
%% gathering an undelimited argument. Thus:
%%
%%   \UD@ExtractFirstArg{  ABCDE} also yields {A}
%%
%%   \UD@ExtractFirstArg{  {AB}CDE} also yields {AB}
%%
%% This routine only works when the argument of \UD@ExtractFirstArg
%% is not empty/when the argument of \UD@ExtractFirstArg does have a
%% first inner undelimited argument. Thus use this routine only in 
%% situations where non-emptiness of \UD@ExtractFirstArg's argument is
%% ensured.
%%.............................................................................
\newcommand\UD@RemoveTillUD@SelDOm{}%
\long\def\UD@RemoveTillUD@SelDOm#1#2\UD@SelDOm{{#1}}%
\newcommand\UD@ExtractFirstArg[1]{%
  \romannumeral0%
  \UD@ExtractFirstArgLoop{#1\UD@SelDOm}%
}%
\newcommand\UD@ExtractFirstArgLoop[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
  { #1}%
  {\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillUD@SelDOm#1}}%
}%
%%=============================================================================
%%  \UD@removeallspace{<argument probably with space tokens>}
%%
%%  after two expansion-steps delivers <argument without space tokens>
%%  
%%  (!!! \UD@removeallspace does also replace all pairs of matching 
%%       explicit character tokens of catcode 1/2 by matching braces!!!)
%%-----------------------------------------------------------------------------
\newcommand\UD@removeallspace[1]{%
  \romannumeral0\UD@RemoveAllSpaceLoop{#1}{}%
}%
\newcommand\UD@RemoveAllSpaceLoop[2]{%
  \UD@CheckWhetherNull{#1}{ #2}{%
    \UD@CheckWhetherLeadingSpace{#1}{%
       \expandafter\UD@RemoveAllSpaceLoop
       \expandafter{\UD@removespace#1}{#2}%
    }{%
      \UD@CheckWhetherBrace{#1}{%
        \expandafter\expandafter\expandafter\UD@PassFirstToSecond
        \expandafter\expandafter\expandafter{%
        \expandafter\UD@PassFirstToSecond\expandafter{%
            \romannumeral0\expandafter\UD@RemoveAllSpaceLoop
            \romannumeral0\UD@ExtractFirstArgLoop{#1\UD@SelDOm}{}%
        }{#2}}%
        {\expandafter\UD@RemoveAllSpaceLoop\expandafter{\UD@firstoftwo{}#1}}%
      }{%
       \expandafter\UD@RemoveAllSpaceLoopPushFirstArgument
       \romannumeral0\UD@ExtractFirstArgLoop{#1\UD@SelDOm}{#1}{#2}%
      }%
    }%
  }%
}%
\newcommand\UD@RemoveAllSpaceLoopPushFirstArgument[3]{%
    \expandafter\UD@RemoveAllSpaceLoop
    \expandafter{\UD@firstoftwo{}#2}{#3#1}%
}%

%% End of code for expandable recursive space-remove-routine.
\makeatother


\makeatletter
\DeclareRobustCommand\compareStrings[2]{%
  % Make sure each instance of \UD@removeallspace gets its argument 
  % expanded - do this by edef-fing while via \noexpand preventing 
  % expansion of \UD@removeallspace:
  \protected@edef\tempA{%
    {\noexpand\UD@removeallspace{#1}}%
    {\noexpand\UD@removeallspace{#2}}%
  }%
  % Now that the arguments for the \UD@removeallspace-instances are expanded,
  % via another \protected@edef have carried out the \UD@removeallspace-instances:
  \protected@edef\tempA{%
    % \lowercase is not expandable, thus does not get expanded
    % /does not get carried out at "e-def-fing-time". 
    % Expansion of anything else but \tempA is prevented via 
    % \noexpand. Within \tempA anything but the \UD@removeallspace-
    % instances is already expanded due to the previous \protected@edef.
    % Thus the only effect of this \protected@edef is carrying
    % out \UD@removeallspace-instances on arguments that were expanded by 
    % the previous \protected@edef.
    \lowercase{\noexpand\ifthenelse{\noexpand\equal\tempA}}%
  }%
  % Now in \tempA the arguments are expanded and space tokens
  % are removed. Thus \tempA expands to a call to \lowercase
  % where the arguments are expanded and thus you don't have
  % control-sequence-tokens any more (whereon \lowercase would have
  % no effect) but character-tokens (whereon \lowwercase does have
  % an effect).
  \tempA{\UD@firstoftwo}{\UD@secondoftwo}%
}
\makeatother

\parindent=0ex
\parskip=\baselineskip

\begin{document}

\verb|\compareStrings{te{s}t}{te { S } T}{equal}{different}| yields:
\compareStrings{te{s}t}{te { S } T}{equal}{different}

\verb|\compareStrings{test}{t E   sT}{equal}{different}| yields:
\compareStrings{test}{t E   sT}{equal}{different}

\verb|\compareStrings{t{es}t}{t{se}t}{equal}{different}| yields:
\compareStrings{t{es}t}{t{se}t}{equal}{different}

\def\test{te{ s} t}%
\def\tset{Ts{ E }t}%
\verb|\def\test{te{ s} t}|\\    
\verb|\def\tset{Ts{ E }t}|

\verb|\compareStrings{\test}{te {s} T}{equal}{different}| yields:
\compareStrings{\test}{te {s} T}{equal}{different}

\verb|\compareStrings{\test}{{tS}eT}{equal}{different}| yields:
\compareStrings{\test}{{tS}eT}{equal}{different}

\verb|\compareStrings{\tset}{t{e} s T}{equal}{different}| yields:
\compareStrings{\tset}{t{e} s T}{equal}{different}

\verb|\compareStrings{\tset}{tS{e}T}{equal}{different}| yields:
\compareStrings{\tset}{tS{e}T}{equal}{different}

\verb|\compareStrings{\tset}{\test}{equal}{different}| yields:
\compareStrings{\tset}{\test}{equal}{different}

\verb|\compareStrings{\test}{\tset}{equal}{different}| yields:
\compareStrings{\test}{\tset}{equal}{different}

Be aware that braces are taken into account, thus:

\verb|\compareStrings{t{es}t}{test}{equal}{different}| yields:
\compareStrings{t{es}t}{test}{equal}{different}

Be aware that \verb|\uppercase| and \verb|\lowercase| are not expandable, thus:

\verb|\compareStrings{\uppercase{test}}{TEST}{equal}{different}| yields:
\compareStrings{\uppercase{test}}{TEST}{equal}{different}

\verb|\compareStrings{\uppercase{test}}{test}{equal}{different}| yields:
\compareStrings{\uppercase{test}}{test}{equal}{different}

\verb|\compareStrings{\lowercase{TEST}}{test}{equal}{different}| yields:
\compareStrings{\lowercase{TEST}}{test}{equal}{different}

\verb|\compareStrings{\lowercase{test}}{test}{equal}{different}| yields:
\compareStrings{\lowercase{test}}{test}{equal}{different}

\end{document}

enter image description here