2

I want to compare the last character of a string with other characters.

If I type

\ifthenelse{\equal{f}{f}}{OK}{NOT OK}

it returns OK. HOWEVER, if I type

\substr{asdf}{-1}{1}

it returns f, BUT

\ifthenelse{\equal{\substr{asdf}{-1}{1}}{f}}{OK}{NOT OK}

says Argument of \equal has an extra }.

Probably the answer is trivial, but I have spent several hours, read dozens of posts, and nothing works.

Thank you very much in advance!

0

2 Answers 2

7

enter image description here

You did not mention it but you appear to be using xstring and ifthen packages. xstring functions are almost always non-expandable and so can not be used in conditionals.

LaTeX provides expandable functions to take characters from a string and do comparisons without needing any package:

\documentclass{article}

\ExplSyntaxOn
\NewDocumentCommand\IfLastEqualTF{mm}{
  \str_if_eq:eeTF {\str_item:nn{#1}{-1}}  {\str_item:nn{#2}{-1}}
  }
\ExplSyntaxOff
\begin{document}

last of asdf = f? \IfLastEqualTF{asdf}{f}{yes}{no}

last of asdf = g? \IfLastEqualTF{asdf}{g}{yes}{no}

last of áéíóú = ú  \IfLastEqualTF{áéíóú}{ú}{yes}{no}

last of áéíóú = ó \IfLastEqualTF{áéíóú}{ó}{yes}{no}

\end{document}

Note this actually just compares the last byte of the utf-8 encoding of each argument. So for non ascii characters it is not actually an equality test but so long as you only need characters in the range of accented European latin script it's safe enough.

To do an actual equality test on the last character would require using commands that are aware of the utf-8 encoding from the \text_... module, I may add something later

8
  • Wow, you impressed me, thank you! If you don't mind, I have another couple of (probably very silly) questions. The function does not work, e.g., when I used special accented letters, like áéíóú. Is there a way to consider non-ASCII characters? And another (probably very ignorant) question: what is the difference between an expandable and a non-expandable function? Is it possible to turn a non-expandable function into an expandable one? Thank you very much again.
    – User
    Commented Jun 16 at 8:55
  • @User I updated for accented characters, on expandability you can search this site or start from tex.stackexchange.com/questions/66118/… Commented Jun 16 at 9:39
  • I can't see a fast way of getting the end of an arbitrary UTF-8 text in an 8-bit engine: will need to use \text_map_function:nN and collect up the last entry - all doable but not that efficient.
    – Joseph Wright
    Commented Jun 16 at 9:57
  • 1
    @JosephWright sure but I think codepoints are often enough, and in pdftex, probably already more than enough:-) Commented Jun 16 at 10:33
  • 1
    @User I see egreg has added a version with \text functions. as I comment in the answer that's more complete, but more complicated:-) But means I won't add another version here Commented Jun 16 at 10:36
3

You can do this expandably, but certainly not with xstring.

The idea is to split the given text into items, bracing them and checking the last item.

\documentclass{article}

\ExplSyntaxOn

\NewExpandableDocumentCommand{\IfLastEqualTF}{mmmm}
 {
  \str_if_eq:eeTF
   { \tl_item:en { \text_map_function:nN { #1 } \__user_brace_items:n } { -1 } } % last item
   { #2 } % item to check against
   { #3 } % true text
   { #4 } % false text
 }

\cs_generate_variant:Nn \tl_item:nn { e }
\cs_new:Nn \__user_brace_items:n { {#1} }

\ExplSyntaxOff

\begin{document}

last of asdf = f? \IfLastEqualTF{asdf}{f}{yes}{no}

last of asdf = g? \IfLastEqualTF{asdf}{g}{yes}{no}

last of áéíóú = ú  \IfLastEqualTF{áéíóú}{ú}{yes}{no}

last of áéíóú = ó \IfLastEqualTF{áéíóú}{ó}{yes}{no}

\IfLastEqualTF{三人}{人}{yes}{no}

\IfLastEqualTF{三人}{三}{yes}{no}

\end{document}

enter image description here

You might branch for Unicode and non Unicode engines, because in the former case the test can be made much more efficient.

\documentclass{article}

\ExplSyntaxOn

\NewExpandableDocumentCommand{\IfLastEqualTF}{mmmm}
 {
  \str_if_eq:eeTF { \__user_lastitem:n { #1 } } { #2 } { #3 } { #4 }
 }

 
\sys_if_engine_pdftex:TF
 {
  \cs_new:Nn \__user_lastitem:n
   {
    \tl_item:en { \text_map_function:nN { #1 } \__user_brace_items:n } { -1 }
   }
 }
 {
  \cs_new:Nn \__user_lastitem:n { \str_item:nn { #1 } { -1 } }
 }

\cs_generate_variant:Nn \tl_item:nn { e }
\cs_new:Nn \__user_brace_items:n { {#1} }

\ExplSyntaxOff

\begin{document}

last of asdf = f? \IfLastEqualTF{asdf}{f}{yes}{no}

last of asdf = g? \IfLastEqualTF{asdf}{g}{yes}{no}

last of áéíóú = ú  \IfLastEqualTF{áéíóú}{ú}{yes}{no}

last of áéíóú = ó \IfLastEqualTF{áéíóú}{ó}{yes}{no}

\IfLastEqualTF{三人}{人}{yes}{no}

\IfLastEqualTF{三人}{三}{yes}{no}

\end{document}
3
  • Thank you. Really impressive. One thing, the code runs beautifully, but, if I write the data in a .csv file and import them by means of \csvreader, it fails. What can be the reason?
    – User
    Commented Jun 16 at 18:16
  • @User Please, open a new question with the details.
    – egreg
    Commented Jun 16 at 19:12
  • Done! tex.stackexchange.com/questions/720728/… Thank you guys for all your feedback!
    – User
    Commented Jun 16 at 21:28

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .