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 can I know if a macro contains a coordinate, that is, in the sense of having the shape of a coordinate num,num.

What I want to do is to know if a given macro, \pos, has the shape (in sense of parsing) of a coordinate or not, and then do something in case it has it and do something else if the shape is not a coordinate. For example, I'm looking for a way of achieving:

\pos{0,0}
\ifcoordinate\pos
It is a coordinate
\else
It is not a coordinate
\fi

In that case, what \ifcoordinate should be? In other words, how can I know if the contents of the given macro are in the sequence: number, coma, number?.

Note that I want to use this verification, later on, in some TikZ related code, so a TikZ related solution is appreciated.

share|improve this question
    
I think this is pretty hard the way you're describing. TeX doesn't have a regular expression engine. All of its ability to analyze strings comes from the actual macros themselves. You can write a parser with macros (like TikZ does), but that seems more trouble than it's worth. –  Matthew Leingang Feb 9 '12 at 13:12
    
The TikZ coordinates have many different forms: x,y, angle:radius, x,y,z, {2*4},{\x/2}, etc. –  Paul Gaborit Oct 3 '12 at 15:19

2 Answers 2

up vote 3 down vote accepted

Here is a version using the xstring package based on @egreg's examples:

This also yields

YES
NO
YES

Known Issues:

  • \IfDecimal allows the decimal separator to be a dot or a comma. Since we uses a comma as a separator for the two numbers, the first coordinate can not use a comma as the decimal separator, but the second one can. This inconsistency is not good so what is needed is a way to change the decimal separator for xtring to just be the period.

Code:

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

\newtoggle{wasCoordinate}
\newcommand*{\ifcoordinate}[3]{%
    \toggletrue{wasCoordinate}%
    \StrBefore{#1}{,}[\StringBeforeComma]
    \StrBehind{#1}{,}[\StringBehindComma]
    \IfDecimal{\StringBeforeComma}{}{\togglefalse{wasCoordinate}}
    \IfDecimal{\StringBehindComma}{}{\togglefalse{wasCoordinate}}
    \iftoggle{wasCoordinate}{#2}{#3}
}%

\begin{document}

\def\pos{1.23,1}
\ifcoordinate{\pos}{YES}{NO}

\def\pos{1.23}
\ifcoordinate{\pos}{YES}{NO}

\def\pos{1.23,-1}
\ifcoordinate{\pos}{YES}{NO}

\end{document}
\end{document}
share|improve this answer
\documentclass{article}
\usepackage{xparse,l3regex}
\ExplSyntaxOn
\NewDocumentCommand\ifcoordinate{ m m m }
  {
   \bool_set_true:N \l_iscoord_bool
   \seq_set_split:Nnx \l_tmpa_seq {,} {#1}
   \int_compare:nTF { \seq_length:N \l_tmpa_seq = 2 }
     {
      \seq_map_inline:Nn \l_tmpa_seq
        { \bool_if:NT \l_iscoord_bool { \iscoord_checkfornumber:n { ##1 } } }
     }
     { \bool_set_false:N \l_iscoord_bool }
   \bool_if:NTF \l_iscoord_bool {#2} {#3}
  }
\cs_generate_variant:Nn \seq_set_split:Nnn { Nnx }
\cs_new:Npn \iscoord_checkfornumber:n #1
  {
   \regex_match:nnTF {\A \-? \d+ (\.\d+)? \Z}{#1}
     {\bool_set_true:N \l_iscoord_bool}
     {\bool_set_false:N \l_iscoord_bool}
  }
\bool_new:N \l_iscoord_bool
\ExplSyntaxOff
\begin{document}

\def\pos{1.23,1}
\ifcoordinate{\pos}{YES}{NO}

\def\pos{1.23}
\ifcoordinate{\pos}{YES}{NO}

\def\pos{1.23,-1}
\ifcoordinate{\pos}{YES}{NO}

\end{document}

This will print

YES
NO
YES

Important change

Due to the changes to expl3 made in Summer 2012, in the code above \seq_length:N should be replaced by \seq_count:N. Here's a new complete implementation.

\documentclass{article}
\usepackage{xparse,l3regex}
\ExplSyntaxOn
\NewDocumentCommand\ifcoordinate{ m m m }
 {
  \iscoord_main:nnn { #1 } { #2 } { #3 }
 }
\bool_new:N \l__iscoord_iscoord_bool
\seq_new:N \l__iscoord_arg_seq
\cs_new_protected:Npn \iscoord_main:nnn #1 #2 #3
  {
   \bool_set_true:N \l__iscoord_iscoord_bool
   \seq_set_split:Nnx \l__iscoord_arg_seq {,} {#1}
   \int_compare:nTF { \seq_count:N \l__iscoord_arg_seq = 2 }
     {
      \seq_map_inline:Nn \l__iscoord_arg_seq 
        { \bool_if:NT \l__iscoord_iscoord_bool { \__iscoord_checkfornumber:n { ##1 } } }
     }
     { \bool_set_false:N \l__iscoord_iscoord_bool }
   \bool_if:NTF \l__iscoord_iscoord_bool {#2} {#3}
  }
\cs_generate_variant:Nn \seq_set_split:Nnn { Nnx }
\cs_new_protected:Npn \__iscoord_checkfornumber:n #1
  {
   \regex_match:nnTF {\A \-? \d+ (\.\d+)? \Z}{#1}
     {\bool_set_true:N \l__iscoord_iscoord_bool}
     {\bool_set_false:N \l__iscoord_iscoord_bool}
  }
\ExplSyntaxOff
\begin{document}

\def\pos{1.23,1}
\ifcoordinate{\pos}{YES}{NO}

\def\pos{1.23}
\ifcoordinate{\pos}{YES}{NO}

\def\pos{1.23,-1}
\ifcoordinate{\pos}{YES}{NO}

\end{document}
share|improve this answer

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.