Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

How do I do a conditional 'if then else' statement, based on length of string being greater than (or less than, or equal) a specified value.

For example, something Like

\def\mystring{XYZ}
\def\mythresh{1}
\ifthenelse{\stringlength{\mystring} > \mythresh}{TRUE}{FALSE}

where \stringlength is 'pseudo' for the relevant command, which I am unsure which is the most widely used.

Does the logical greater than operator apply here, or is there another command?

share|improve this question
    
What do you mean by string length (TeX doesn't really have strings) do you mean the length when typeset (so \mythresh would be a length like 1cm) or do you mean number of characters (so \mythresh would be a number like 3) In the latter case what is the length of \'{e}\textcolor{red}{f}z ? Typeset length is the easiest to measure (or define) –  David Carlisle Dec 19 '12 at 15:22
    
I Mean Number of Characters... –  Nicholas Hamilton Dec 19 '12 at 15:26
    
so what's the length of \'{e}\textcolor{red}{f}z (There are several possible answers, some of which are easier to code than others) It can't happen, all input is ascii text with no markup would be one answer.... –  David Carlisle Dec 19 '12 at 15:31
1  
@ADP Just check if the argument is empty, which is easier than counting the number of characters. –  egreg Dec 19 '12 at 15:37
1  
Which goes to show it's best to ask a question for what you need rather that one step in one possible way of solving it:-) Werner's answer is fine for the question asked but it invokes a rather large sledgehammer of the xstring and xifthen packages for \ifx\valign#1\valign which will test that #1 is empty (as long as it isn't \valign) in a single expansion step. –  David Carlisle Dec 19 '12 at 15:42
show 4 more comments

4 Answers

up vote 9 down vote accepted

Use the xstring package:

enter image description here

\documentclass{article}
\usepackage{xstring,xifthen}% http://ctan.org/pkg/{xstring,xifthen}
\begin{document}
\def\mystring{XYZ}
\StrLen{\mystring}[\mystringlen]
\def\mythresh{1}
\ifthenelse{\mystringlen > \mythresh}{TRUE}{FALSE}
\def\mythresh{3}
\ifthenelse{\mystringlen > \mythresh}{TRUE}{FALSE}
\end{document}

\StrLen{<stuff>}[<name>] stores the length of <stuff> in the control sequence <name>.

The use of xifthen is not really necessary. See How to form “if … or … then” conditionals in TeX? and the related Why is the ifthen package obsolete? for alternatives.

share|improve this answer
    
Thanks Champ, Worked Perfectly. –  Nicholas Hamilton Dec 19 '12 at 15:31
add comment

Werner's answer answers the question as stated, and I'm not suggesting you unaccept it, but as clarified in comments the actual aim was to check that an input argument has more than (say) 3 characters. That is much simpler and doesn't involve counting anything.

To give an example, the following document shows a direct test that the fourth position is not empty followed by the test using xstring.

In both cases the tests show N for ab and Y for abcd but defining the test and executing the two tests one way takes 70 lines of log file, doing it the other way takes 2360 lines of log output. \tracingall output is usually a fair indication of actual TeX speed, and it's an interesting read anyway to see what TeX is doing behind the scenes.

\documentclass{article}

\tracingall
% check at least four characters

\makeatletter

\def\strcheck#1{\xstrcheck#1{}{}{}{}\xstrcheck}
\def\xstrcheck#1#2#3#4#5\xstrcheck{%
   \ifx\valign#3\valign
     \expandafter\@secondoftwo
   \else
     \expandafter\@firstoftwo
   \fi}


\strcheck{ab}{\show Y}{\show N}
\strcheck{abcd}{\show Y}{\show N}


\makeatother

\usepackage{xstring,xifthen}

\def\strcheckb#1{%
\StrLen{#1}[\mystringlen]%
\ifthenelse{\mystringlen > 3}}


\strcheckb{ab}{\show Y}{\show N}
\strcheckb{abcd}{\show Y}{\show N}

\stop
share|improve this answer
    
Thanks David, I certainly appreciate how you have explained things. Regarding the inefficiencies, such is the nature of generalizations. The letter compiles in such a minuscule fraction of a second, that it is hardly worth worrying about 2190 lines of log... –  Nicholas Hamilton Dec 20 '12 at 0:43
1  
One test will not make a measurable difference but I learnt TeX at a time when taking 15 minutes per page to process a document was common, and old habits die hard, and a test file may only have one comparison but if you use such a thing in the inner loop of a package like l3xxx or pgfxxx then a single document can easily be doing several thousand such calculations and these things do add up. –  David Carlisle Dec 20 '12 at 0:50
add comment

In support of David Carlisle's comment: even a more general solution like the following shows less than 200 lines of trace log.

\documentclass{article}
\makeatletter
% \getStringLength{<string>}{<returned length>}
\def\getStringLength#1#2{%
  \begingroup\@tempcnta\z@
  \let\x\g@tStringLength
  \ifx\g@tStringLength#1\g@tStringLength
    \def\x##1\g@tStringLength{\endgroup\def#2{0}}%
  \fi
  \x#2#1\g@tStringLength
}
\def\g@tStringLength#1#2#3{%
  \advance\@tempcnta\@ne
  \ifx\g@tStringLength#3%
    \edef#1{\endgroup\def\noexpand#1{\the\@tempcnta}}#1%
  \else
    \expandafter\g@tStringLength\expandafter#1\expandafter#3%
  \fi
}
\makeatother
\begin{document}
{\tracingall
   \getStringLength{ab}\length
   \ifnum\length=4 Y\else N\fi
}

\getStringLength{abcd}\length
\ifnum\length=4 Y\else N\fi

\getStringLength{}\length
\end{document}
share|improve this answer
add comment

David, Ahmed, whilst I appreciate the elegance of your demonstration, the solution that solved my problem was achieved in only 3 lines of code...

\def\todayDate{1st January 1999} %leave empty for today's date.
\StrLen{\todayDate}[\mystringlen]
\ifthenelse{\mystringlen > 3}{\renewcommand{\today}{\todayDate}}{}

However, to cover all bases, a command that simply checks if the variable is empty is as follows, in one fewer line and not making a call to the 'StrLen' command.

\def\todayDate{1st January 1999} %leave empty for today's date.
\ifthenelse{\equal{\todayDate}{}}{}{\renewcommand{\today}{\todayDate}}
share|improve this answer
    
I imagine that you know this but, to be fair, the strlen macro is implemented with hundreds of lines of code. –  Scott H. Dec 20 '12 at 6:44
    
Hence the main contention of this thread, and why, I decided to acknowledge a method that DOESN'T use StrLen... –  Nicholas Hamilton Dec 20 '12 at 6:57
    
One has to be amazed at why this very problem is sooooo trivial in other OOP languages (IE count it directly String s = new String("BLA"), int length = s.length(), or split into array int l = s.toArray().length()), yet amazingly non-trivial in LaTeX... –  Nicholas Hamilton Dec 20 '12 at 7:01
    
Ok, but now you're using ifthenelse.sty! Any way you slice it you're using more lines of code than the 8-9 that were offered above. –  Scott H. Dec 20 '12 at 7:07
    
@Scott H., So how would you do it then. –  Nicholas Hamilton Dec 20 '12 at 7:10
show 2 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.