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.

I try to extract the year, month and day from a string and write different text depending on the given date. I thought I could use xstring and etoolbox, but I can'st get it to work. Here's the code snippet:

\usepackage{xstring}
\usepackage{etoolbox}

\begin{document}
\newcommand{\Datum}{04.12.2011}

\newcommand{\Jahr}{\StrBehind[2]{\Datum}{.}}
\newcommand{\Monat}{\StrBetween[1,2]{\Datum}{.}{.}}
\newcommand{\Tag}{\StrBefore[1]{\Datum}{.}}

Jahr: \Jahr

\ifnumcomp{\Jahr}{=}{2011}{Jahr eq 2011}{Jahr neq 2011}

Which gives the following error:

pdflatex> ! Missing number, treated as zero.
pdflatex> <to be read again> 
pdflatex>                    \let 
pdflatex> l.11 {305}
pdflatex>           
pdflatex> ! Missing = inserted for \ifnum.
pdflatex> <to be read again> 

But \Jahr seems to correctly contain 2011.

share|improve this question
    
Welcome to TeX.SE. When asking questions about problems one is encountering with (La)TeX code, it is helpful to provide a complete Minimum Working Example (MWE) rather than code snippets. To help debug problems, it's generally also helpful to provide information about the TeX distribution one is using. –  Mico Jan 29 '12 at 20:17
add comment

3 Answers

up vote 7 down vote accepted

Please avoid providing code snippets; instead, do create a complete MWE.

You are passing the complete xstring-test to ifnumcomp. That fails. You can save the the result of the xstring-test by the optional argument of \StrBehind and pass this to \ifnumcomp:

\documentclass{article}
\usepackage{xstring}
\usepackage{etoolbox}

\begin{document}
\newcommand{\Datum}{04.12.2011}

\StrBehind[2]{\Datum}{.}[\Jahr]
\StrBetween[1,2]{\Datum}{.}{.}[\Monat]
\StrBefore[1]{\Datum}{.}[\Tag]

Jahr: \Jahr

\ifnumcomp{\Jahr}{=}{2011}{Jahr eq 2011}{Jahr neq 2011}
\end{document}

Maybe you want to combine the output and the test you can use:

\documentclass{article}
\usepackage{xstring}
\usepackage{etoolbox}
\makeatletter
\newcommand\Datum[1]{\@datum{#1}\@executetest{#1}}
\def\@datum#1{#1}
\def\@executetest#1{%
\StrBehind[2]{#1}{.}[\Jahr]
\StrBetween[1,2]{#1}{.}{.}[\Monat]
\StrBefore[1]{#1}{.}[\Tag]
}
\begin{document}
\Datum{04.12.2011}

Jahr: \Jahr

\ifnumcomp{\Jahr}{=}{2011}{Jahr eq 2011}{Jahr neq 2011}
\end{document}
share|improve this answer
    
Wow, thanks, that was quick! –  Tom Jan 29 '12 at 21:43
add comment

Modern parsing packages take care of some things that probably should be taken care of, but sometimes (or just as an illustrative example) it's simpler to use the TeX primitives directly:

\documentclass{article}

\def\datum{04.12.2011}

\def\Jahr{\expandafter\xJahr\datum\relax}
\def\Monat{\expandafter\xMonat\datum\relax}
\def\Tag{\expandafter\xTag\datum\relax}

\def\xJahr#1.#2.#3\relax{#3}
\def\xMonat#1.#2.#3\relax{#2}
\def\xTag#1.#2.#3\relax{#1}

\begin{document}


Jahr: \Jahr

\ifnum\Jahr=2011
Jahr eq 2011
\else
Jahr neq 2011
\fi

\end{document}
share|improve this answer
1  
+1 for not shooting with cannon balls on sparrows and a good example of using TeX directly for parsing. For the sake of the "illustrativeness" of the example you might want to consider adding a bit of explanation to aid the beginner (e.g., how TeX matches argument patterns and the roles of \expandafter and \relax). –  Daniel Jan 30 '12 at 8:42
    
\expandafter makes \datum expand before \xJahr, so \Jahr is equivalent to \xJahr 04.12.2011\relax then \xJah takes three arguments delimited by . or \relax and returns one of them. The \relax token is just used as a token to mark the end of the input here, it's never actually executed, and using an undefined command or a . or \documentclass would have worked just as well, so long as \xJah is defined to consume everything up to the token inserted by \Jahr. –  David Carlisle Jan 30 '12 at 10:27
1  
David, I would suggest to edit this information into your answer (and then delete the comment, as will I do with mine). –  Daniel Jan 30 '12 at 17:25
add comment

A different implementation with xparse:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\datetest}{ O{\Datum} m m m }
  {
   \seq_set_split:Nnx \l_datetest_date_seq { . } { #1 }
   \int_compare:nTF { \datetest_get:n { #2 } #3 #4 }
  }
\cs_new:Npn \datetest_get:n #1
  {
   \prg_case_str:nnn { #1 }
     {
      { Jahr }  { \seq_item:Nn \l_datetest_date_seq { 2 } }
      { Monat } { \seq_item:Nn \l_datetest_date_seq { 1 } }
      { Tag }   { \seq_item:Nn \l_datetest_date_seq { 0 } }
     }
     { 0 }
  }
\seq_new:N \l_datetest_date_seq
\cs_generate_variant:Nn \seq_set_split:Nnn { Nnx }
\ExplSyntaxOff


\newcommand{\Datum}{04.8.2011}

\begin{document}

\datetest{Jahr}{=}{2011}{Jahr eq 2011}{Jahr neq 2011}

\datetest{Monat}{<=}{9}{$\le$}{$>$}

\newcommand{\mydate}{01.02.2003}

\datetest[\mydate]{Monat}{>}{3}{After March}{Before April}

\datetest[01.05.2010]{Monat}{>}{3}{After March}{Before April}
\end{document}

\datetest acts by default on \Datum, but a macro or an explicit date can be passed as optional argument. The item to test is the first argument, the type of test (<, <=, =, >=, or >) as second argument; then the number to test and what to do if the test is either true or false.

Note that the second argument is a string, not a command. One can extend the macros to define \Jahr, \Monat or \Tag, if so desired.

share|improve this answer
    
+1. Rather than \tl_set:Nx and \tl_replace_all:Nnn, I'd use \seq_set_split:Nnx \l_foo_seq {.} {#1}, then use \seq_item:Nn where you used \clist_item:Nn. It is cleaner because you are not converting a tl into a clist by hand. By the way, \clist_set:Nn \l_foo_clist { a~, } results in \l_foo_clist containing a only, so a clist is not simply a token list with some commas. –  Bruno Le Floch Jan 30 '12 at 7:25
    
@BrunoLeFloch Thanks, \seq_set_split is just what I was looking for. –  egreg Jan 30 '12 at 9:55
add comment

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.