6

My question is simple but I don't know any simple solution for it.

I have an unknown variable namely \unknown and a variable which I want to compare \unknown with it, namely \test.

I want a command like \aresame to compare them. For example, consider:

\def\test{Five}
\def\unknown{{{F}I{V}E{}}}
\def\unknownb{Four}
\def\unknownc{{\unknownb}}
\aresame{\unknown}{\test}
\aresame{\test}{\unknown}
\aresame{\unknownb}{\test}
\aresame{\unknownb}{Four}
\aresame{\unknownb}{\unknownc}

And when I run the code, I want the command that gives me TRUE, for the first comparision, not false since, although they meybe different in many aspects, both are the same to me.

I expect the results be as follows:

TRUE
TRUE
FALSE
TRUE
TRUE

2 Answers2

11

Well your question is not simple. At first you didn't explain what you mean by "same for you" so the rules for your "fuzzy" comparision are quite unclear. And at second you didn't explain what content your variables can have. Things can get very difficult if arbitrary TeX-commands are allowed. For your example the following works:

\documentclass{article}
\usepackage{xparse}
\begin{document}
\newcommand\test{Five}
\newcommand\unknown{{{F}I{V}E{}}}
\newcommand\unknownb{Four}

\ExplSyntaxOn
\NewDocumentCommand\aresame { m m }
{
 \tl_set_rescan:Nnx \l_tmpa_tl 
  {
   \char_set_catcode_ignore:N \{                               
   \char_set_catcode_ignore:N \}
  } 
  {#1}
 \tl_set_rescan:Nnx \l_tmpb_tl
  {
   \char_set_catcode_ignore:N \{
   \char_set_catcode_ignore:N \}
  }
  {#2} 
  \tl_set:Nx\l_tmpa_tl {\str_fold_case:V \l_tmpa_tl}
  \tl_set:Nx\l_tmpb_tl {\str_fold_case:V \l_tmpb_tl}
  \tl_if_eq:NNTF \l_tmpa_tl\l_tmpb_tl {yes} {no}
 } 

\ExplSyntaxOff


\aresame{\test}{\unknown}

\aresame{\test}{\unknownb}
\end{document}
Joseph Wright
  • 259,911
  • 34
  • 706
  • 1,036
Ulrike Fischer
  • 327,261
5

A (weaker) version of Ulrike's code that works also in TeX Live 2013; the assumption is that < and > don't appear in the strings you want to compare.

\documentclass{article}

\makeatletter \newcommand{\aresame}[2]{% \aresame@massage\aresame@tempa{#1}% \aresame@massage\aresame@tempb{#2}% \ifx\aresame@tempa\aresame@tempb \expandafter@firstoftwo \else \expandafter@secondoftwo \fi }

\def\aresame@massage#1#2{% \begingroup\let@xp\expandafter\let@nx\noexpand \everyeof{}% \catcode{=9 \catcode}=9 \catcode&lt;=1 \catcode>=2 \begingroup\edef\x{% \endgroup@nx\scantokens{\def@nx\1<#2>@nx\empty}% }\x \uppercase@xp{@xp\endgroup@xp\def@xp#1@xp{\1}}% } \makeatother

\begin{document}

\def\test{Five} \def\unknown{{{F}I{V}E{}}} \def\unknownb{Four} \def\unknownc{{\unknownb}}

--\aresame{\unknown}{\test}{TRUE}{FALSE}--\par --\aresame{\test}{\unknown}{TRUE}{FALSE}--\par --\aresame{\unknownb}{\test}{TRUE}{FALSE}--\par --\aresame{\unknownb}{Four}{TRUE}{FALSE}--\par --\aresame{\unknownb}{\unknownc}{TRUE}{FALSE}--\par

\end{document}

A different implementation where braces are recursively stripped off, with full expansion, and finally the token list is treated as a string which is uppercased.

\documentclass{article}

\ExplSyntaxOn

\tl_new:N \l__omid_strip_in_tl \tl_new:N \l__omid_strip_out_tl \str_new:N \l__omid_strip_a_str \str_new:N \l__omid_strip_b_str

\cs_new_protected:Nn \omid_strip_braces:Nn { \tl_set:Ne \l__omid_strip_in_tl { #2 } __omid_strip_braces:N #1 } \cs_new_protected:Nn __omid_strip_braces:N { \tl_clear:N \l__omid_strip_out_tl \tl_map_function:NN \l__omid_strip_in_tl __omid_strip_add:n \tl_if_eq:NNTF \l__omid_strip_in_tl \l__omid_strip_out_tl { \str_set:NV #1 \l__omid_strip_out_tl \str_set:Ne #1 { \str_uppercase:f { #1 } } } { \tl_set_eq:NN \l__omid_strip_in_tl \l__omid_strip_out_tl __omid_strip_braces:N #1 } } \cs_new_protected:Nn __omid_strip_add:n { \tl_put_right:Nn \l__omid_strip_out_tl { #1 } }

\NewDocumentCommand{\aresame}{mmmm} { \omid_strip_braces:Nn \l__omid_strip_a_str { #1 } \omid_strip_braces:Nn \l__omid_strip_b_str { #2 } \str_if_eq:NNTF \l__omid_strip_a_str \l__omid_strip_b_str { #3 } { #4 } }

\ExplSyntaxOff

\begin{document}

\def\test{Five} \def\unknown{{{F}I{V}E{}}} \def\unknownb{Four} \def\unknownc{{\unknownb}}

--\aresame{\unknown}{\test}{TRUE}{FALSE}--\par --\aresame{\test}{\unknown}{TRUE}{FALSE}--\par --\aresame{\unknownb}{\test}{TRUE}{FALSE}--\par --\aresame{\unknownb}{Four}{TRUE}{FALSE}--\par --\aresame{\unknownb}{\unknownc}{TRUE}{FALSE}--\par

\end{document}

egreg
  • 1,121,712
  • It works for the example. But when I tested it with something more serious I got an error! When I print \pageref{lastpreamblepage} I see هشت. When I tried to `\def\unknownb{\pageref{lastpreamblepage}}and\def\test{هشت}. I got an error runing the file. Can you check this also? The error is shown as follow:! Use of \reserved@a doesn't match its definition. \new@ifnextchar ...served@d = #1\def \reserved@a { #2}\def \reserved@b {#3}\f... l.138 --\aresame{\unknownb}{\test} {TRUE}{FALSE}--\par ?` – Omid Ghayour Sep 16 '16 at 10:20
  • 1
    @OmidGhayour You can't use \pageref* in the arguments to \aresame. You're probably using the wrong approach to the problem. Try loading the refcount package and using \getpagerefnumber instead of \pageref*. – egreg Sep 16 '16 at 10:28